using com.yoozoo.gta.Extension;
using com.youzu.got.protocol;
using Gameplay.PVE.Utils;
using LogSystem;
using System;
using System.Collections.Generic;
using Neonagee.LocalPreferences;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Profiling;
using Yoozoo.Gameplay.RTS.Proto;
using Yoozoo.Mars.Got.SpriteAnim;
using Random = Unity.Mathematics.Random;

namespace Yoozoo.Gameplay.RTS
{
    public class SquareDataManager
    {
        private static SquareDataManager m_instance;

        public static bool Enabled = true;

        /// <summary>
        /// 0 正常update
        /// 1 下一帧停止update
        /// 2 停止update
        /// </summary>
        private int updateState = 0;

        //选项里设置，保存在本地
        public static bool isDebug = false;

        public static bool isSpriteJobs = true;

        private Transform debugRoot;
        private List<Transform> squares;
        private List<Transform> children;
        private bool _isDisposed = false;
        public bool animSpriteDataChanged = false;

        public static float CustomLifeTime;

        private bool isParticleDebug = true;
        
        public static SquareDataManager Instance
        {
            get
            {
                if (m_instance == null)
                {
                    m_instance = new SquareDataManager();
                }

                return m_instance;
            }
        }

        public MarchSquareNativeData marchNativeData;
        public ChildBehaviourNativeData childNativeData;

        public BattleFormationCfg[] localPositions;
        private NativeArray<int> localPositionsNativeIndex;
        private NativeArray<float3> localPositionsNative;
        private NativeArray<float3> battlePositionsNative;

        private struct FormationData
        {
            public BattleFormationCfg config;
            public int formationId;
        }

        private readonly Dictionary<int, List<FormationData>> formationIdDic =
            new Dictionary<int, List<FormationData>>();

        public List<AnimSprite> animSprites = new List<AnimSprite>();
        //public List<AnimSprite> shadowSprites = new List<AnimSprite>();

        private int currentMarchIndex;
        private int currentChildIndex;

        private float animSpriteScale => RTSMono.Instance.SoldierScale;

        private bool attackDataReady = false;
        private bool spriteDataReady = false;

        private NativeArray<int> soldierPositionIndexNativeArrays;
        //战斗相关

        private Dictionary<int, SoldierAttackActionConfig> attackActionConfigs;
        private Dictionary<int, ISubAction[]> attackActions;



        //1.根据soldierType获取SoldierAttackActionConfig
        //2.随机一个instructionIndex
        //3.根据instructionIndex得到instructionId
        //4.根据instructionId从attackActions里得到ISubActions
        //5.根据actionId从ISubAtions里得到subAction
        private NativeHashMap<int, SoldierAttackActionConfigData> attackActionConfigData;
        private NativeArray<int> useActionIds;
        private NativeHashMap<int, AttackActionConfigData> attackActionData;
        private NativeArray<AttackActionInfoData> actionInfos;
        private NativeArray<float3> directions;
        private NativeArray<float3> directions8;
        private Random random;

        //序列帧
        private List<AnimSpriteData> animSpriteData;
        private Dictionary<string, int> spriteNameToPSIndexDic;
        private Dictionary<int, string> psIndexToSpriteNameDic;

        private List<int> recoverSquareList = new List<int>();

        public static int MAX_MARCH_COUNT = 1000;
        public static int MAX_CHILD_COUNT = 10000;

        private static int marchNativeArrayLength = (int) (MAX_MARCH_COUNT * BattleUtils.NativeArrayInitRatio);
        private static int childNativeArrayLength = (int) (MAX_CHILD_COUNT * BattleUtils.NativeArrayInitRatio);

        public static void SetMaxCount(int marchCount, int childCount)
        {
            MAX_MARCH_COUNT = marchCount;
            MAX_CHILD_COUNT = childCount;
            marchNativeArrayLength = (int) (marchCount * BattleUtils.NativeArrayInitRatio);
            childNativeArrayLength = (int) (childCount * BattleUtils.NativeArrayInitRatio);
            //ResizeNativeArray();
        }

        private class FakeKnockBackData
        {
            public AnimSprite animSprite;
            public Vector3 startPosition;
            public Vector3 startForward;
            public float verticalStartSpeed;
            public float verticalA;
            public float horizontalDistance;
            public float startKnockTime;
            public float startFadeTime;
            public int psIndex;
        }

        private class AmbulanceData
        {
            public AnimSprite animSprite;
            public List<int> childIndex;
            public int marchIndex;
            public Vector3 startPosition;
            public Vector3 position;
            public int state;
            public int fadeState;
            public float startFadeTime;
            public float initSize;
        }

        private List<FakeKnockBackData> fakeKnockBackList = new List<FakeKnockBackData>();
        private List<AmbulanceData> ambulanceList = new List<AmbulanceData>();

        private class CrossingGateFormationData
        {
            public List<AnimSprite> sprites = new List<AnimSprite>();
            public Vector3 forward;
            public List<Vector3> offsets = new List<Vector3>();
            public List<int> psIndex = new List<int>();
            public int marchIndex;
            public int fadeState;
            public float startFadeTime;
            public float initSize;
            public bool resReady;
            public int team;
            public bool valid;
        }

        private Dictionary<int,CrossingGateFormationData> crossingGateList = new Dictionary<int,CrossingGateFormationData>();
        private List<int> crossingGateDeleteList = new List<int>();
        private List<CrossingGateFormationData> crossingGateDataPool = new List<CrossingGateFormationData>();

        //key = childIndex;  value = 加载图集生成小兵精灵的回调
        private Dictionary<int, Action<CreatorVisitor>> loadSoldierAtlasCallBackMap = new Dictionary<int, Action<CreatorVisitor>>();
        
        //货车结构
        private class TruckData
        {
            public AnimSprite animSprite;
            public int childIndex;
            public Vector3 startPosition;
            public Vector3 targetPosition;
            public Vector3 position;
            public Vector3 forward;
            public int state;
            public float startFadeTime;
            public bool resReady;
            public bool valid;
            public float speed;
            public int psIndex;
            public float initSize;
        }
        
        private Dictionary<int,TruckData> truckDataDic = new Dictionary<int, TruckData>();
        
        public void EndDebug()
        {
            LocalPrefs.SetInt("SquareDataManagerDebug", 0);
            if (debugRoot)
            {
                GameObject.Destroy(debugRoot.gameObject);
                debugRoot = null;
            }

            for (int i = 0; i < children.Count; i++)
            {
                if (children[i] && children[i].Valid())
                {
                    GameObject.Destroy(children[i].gameObject);
                }
            }

            for (int i = 0; i < squares.Count; i++)
            {
                if (squares[i] && squares[i].Valid())
                {
                    GameObject.Destroy(squares[i].gameObject);
                }
            }

            squares.Clear();
            children.Clear();
            isDebug = false;
        }

        public void StartDebug()
        {
            LocalPrefs.SetInt("SquareDataManagerDebug", 1);
            if (isDebug)
            {
                return;
            }

            isDebug = true;
            InitDebug();
            var marches = ArmyManager.Instance.MarchManager.Marches;
            for (int i = 0; i < marches.Count; i++)
            {
                int index = marches[i].squareDataIndex;
                //if (squares[i] == null || !squares[i].Valid())
                {
                    var square = AddDebugSquare(index, marches[i].Tid,marches[i].TargetCoordinateType);
                    squares[index] = square;
                }
                var childHead = marchNativeData.childIndexHead[index];
                var childCount = marchNativeData.childCount[index];
                for (int j = childHead; j < childCount + childHead; j++)
                {
                    if (children[j] == null)
                    {
                        children[j] = AddDebugChildren(j);
                    }

                    children[j].transform.SetParent(squares[i]);
                }
            }
        }

        private void InitDebug()
        {
            debugRoot = new GameObject("[SquareDataRoot]").transform;
            squares = new List<Transform>();
            for (int i = 0; i < marchNativeData.count; i++)
            {
                squares.Add(null);
            }

            children = new List<Transform>();
            for (int i = 0; i < childNativeData.count; i++)
            {
                children.Add(null);
            }
        }

        private Transform AddDebugSquare(int index, long marchId,TargetCoordinateType type)
        {
            var go = new GameObject("square"+index.ToString());
            go.AddComponent<SquareDataEditor>().index = index;
            var marchObject = ArmyManager.Instance.MarchManager.GetMarchEntityByIdAndType(marchId,type);
            var trans = go.transform;
            if (marchObject != null)
            {
                trans.SetParent(marchObject.Transform);
            }
            else
            {
                trans.transform.SetParent(debugRoot);
            }

            return trans;
        }

        private Transform AddDebugChildren(int index)
        {
            var go = new GameObject(index.ToString());
            go.AddComponent<ChildDataEditor>().index = index;
            var trans = go.transform;
            children[index] = trans;
            if (showSphere)
            {
                AddSphere(trans);
            }

            return trans;
        }

        public void InitSoldierAttackActionConfig(Dictionary<int, SoldierAttackActionConfig> attackActionConfigs)
        {
            Profiler.BeginSample(("InitSoldierAttackActionConfig"));
            this.attackActionConfigs = attackActionConfigs;
            CheckInitAttackActionNativeData();
            Profiler.EndSample();
        }


        public void InitAttackActions()
        {
            Profiler.BeginSample(("InitAttackActions"));
            attackActions = ArmyManager.Instance.ResourceManager.JsonManager.CloneAllSubAction();
            CheckInitAttackActionNativeData();
            Profiler.EndSample();
        }

        private void CheckInitAttackActionNativeData()
        {
            if (attackActions != null && attackActionConfigs != null)
            {
                attackDataReady = true;
                int count = 0;
                attackActionData =
                    new NativeHashMap<int, AttackActionConfigData>(attackActions.Count, Allocator.Persistent);
                var list = new List<AttackActionInfoData>();
                foreach (var item in attackActions)
                {
                    for (int i = 0; i < item.Value.Length; i++)
                    {
                        list.Add(new AttackActionInfoData
                        {
                            animType = item.Value[i].actionInfo.animType,
                            time = item.Value[i].actionInfo.time,
                            type = item.Value[i].actionInfo.type,
                        });
                    }

                    attackActionData[item.Key] = new AttackActionConfigData
                    {
                        actionID = item.Key,
                        actionsHead = count,
                        actionsLength = item.Value.Length,
                    };
                    count += item.Value.Length;
                }

                actionInfos = new NativeArray<AttackActionInfoData>(count, Allocator.Persistent);
                for (int i = 0; i < list.Count; i++)
                {
                    actionInfos[i] = list[i];
                }

                count = 0;
                var l = new List<int>();
                attackActionConfigData =
                    new NativeHashMap<int, SoldierAttackActionConfigData>(attackActionConfigs.Count,
                        Allocator.Persistent);
                foreach (var item in attackActionConfigs)
                {
                    for (int i = 0; i < item.Value.useActionId.Length; i++)
                    {
                        l.Add(item.Value.useActionId[i]);
                    }

                    attackActionConfigData[count] = new SoldierAttackActionConfigData
                    {
                        soldierType = item.Value.soldierType,
                        counterPercent = item.Value.counterPercent,
                        specialPercent = item.Value.specialPercent,
                        specialTimes = item.Value.specialTimes,
                        useActionIdHead = count,
                        useActionIdLength = item.Value.useActionId.Length,
                    };
                    count += item.Value.useActionId.Length;
                }

                useActionIds = new NativeArray<int>(count, Allocator.Persistent);
                for (int i = 0; i < l.Count; i++)
                {
                    useActionIds[i] = l[i];
                }
            }
        }

        public void PreloadFormation(Dictionary<int, List<BattleFormationCfg>> configs)
        {
            formationIdDic.Clear();
            int count = 0;
            foreach (var item in configs)
            {
                count += item.Value.Count;
            }

            localPositions = new BattleFormationCfg[count];
            int index = 0;
            int totalCount = 0;
            localPositionsNativeIndex = new NativeArray<int>(count, Allocator.Persistent);
            foreach (var item in configs)
            {
                var formationId = item.Key;
                var list = new List<FormationData>();
                formationIdDic.Add(formationId, list);
                for (int i = 0; i < item.Value.Count; i++)
                {
                    var config = item.Value[i];
                    var id = index;
                    list.Add(new FormationData
                    {
                        formationId = id,
                        config = config,
                    });
                    localPositions[index] = config;
                    localPositionsNativeIndex[index] = totalCount;
                    for (int j = 0; j < config.soldierLocation.Count; j++)
                    {
                        totalCount++;
                    }

                    index++;

                    if (!freeIndexDictionary.ContainsKey(config.modelNum))
                    {
                        freeIndexDictionary.Add(config.modelNum, new Stack<int>());
                    }
                }
            }

            localPositionsNative = new NativeArray<float3>(totalCount, Allocator.Persistent);
            battlePositionsNative = new NativeArray<float3>(totalCount, Allocator.Persistent);
            totalCount = 0;
            for (int i = 0; i < count; i++)
            {
                for (int j = 0; j < localPositions[i].soldierLocation.Count; j++)
                {
                    if (localPositions[i].soldierLocation.Count > j)
                    {
                        localPositionsNative[totalCount] = localPositions[i].soldierLocation[j].pos;
                    }
                    else
                    {
                        Debug.LogError(localPositions[i].formationType+" soldierLocation数目不对，@德哥");
                    }
                    if (localPositions[i].battleSoldierLocation.Count > j)
                    {
                        battlePositionsNative[totalCount] = localPositions[i].battleSoldierLocation[j].pos;
                    }
                    else
                    {
                        Debug.LogError(localPositions[i].formationType+" fightLocation数目不对，@德哥");
                    }

                    totalCount++;
                }
            }
        }

        public int CalculateFormationId(int formationType, int soldierCount)
        {
            bool fixedSoldierID = false;
            int formationId = 0;
            if (formationIdDic.TryGetValue(formationType, out var formationCfgs))
            {
                for (int i = 0; i < formationCfgs.Count; i++)
                {
                    var cfg = formationCfgs[i];
                    formationId = cfg.formationId;
                    if (soldierCount <= cfg.config.soldierNum || RTSQualityHelper.IsSimpleMode && cfg.config.soldierNum == -1 && soldierCount != 0)
                    {
                        return formationId;
                    }
                }
            }

            return formationId;
        }


        private MarchSquareNativeData CreateMarchNativeData(int count)
        {
            return new MarchSquareNativeData
            {
                count = count,
                inited = true,
#if UNITY_EDITOR
                marchId = new NativeArray<ulong>(count, Allocator.Persistent),
#endif
                valid = new NativeArray<bool>(count, Allocator.Persistent),
                position = new NativeArray<float3>(count, Allocator.Persistent),
                forward = new NativeArray<float3>(count, Allocator.Persistent),
                index = new NativeArray<int>(count, Allocator.Persistent),
                childIndexHead = new NativeArray<int>(count, Allocator.Persistent),
                formationPositionIndexOffset = new NativeArray<int>(count,Allocator.Persistent),
                childCount = new NativeArray<int>(count, Allocator.Persistent),
                formationId = new NativeArray<int>(count, Allocator.Persistent),
                TurnState = new NativeArray<int>(count, Allocator.Persistent),
                needCalculateChildren = new NativeArray<bool>(count, Allocator.Persistent),
                needForceMoveChildren = new NativeArray<bool>(count, Allocator.Persistent),
                speed = new NativeArray<float>(count, Allocator.Persistent),
                squareStartPosition = new NativeArray<float3>(count, Allocator.Persistent),
                squareEndPosition = new NativeArray<float3>(count, Allocator.Persistent),
                segmentStartTime = new NativeArray<float>(count, Allocator.Persistent),
                currentSegmentDuration = new NativeArray<float>(count, Allocator.Persistent),
                status = new NativeArray<int>(count, Allocator.Persistent),
                changeStatusFlag = new NativeArray<bool>(count, Allocator.Persistent),
                team = new NativeArray<int>(count, Allocator.Persistent),
                alpha = new NativeArray<float>(count, Allocator.Persistent),
                overrideAlpha = new NativeArray<bool>(count, Allocator.Persistent),
                initSoldierNum = new NativeArray<int>(count, Allocator.Persistent),
                curSoldierNum = new NativeArray<int>(count, Allocator.Persistent),
                soldierTypeList = new NativeArray<uint>(count, Allocator.Persistent),
                isServerPosChange = new NativeArray<bool>(count, Allocator.Persistent),
                isBesiege = new NativeArray<bool>(count, Allocator.Persistent),
                isClientInBattle = new NativeArray<bool>(count, Allocator.Persistent),
                isEscape = new NativeArray<bool>(count, Allocator.Persistent),
                //pathData = new NativeArray<MarchPathData>(count,Allocator.Persistent),
            };
        }

        private ChildBehaviourNativeData CreateChildNativeData(int count)
        {
            return new ChildBehaviourNativeData
            {
                count = count,
                inited = true,
                valid = new NativeArray<bool>(count, Allocator.Persistent),
                index = new NativeArray<int>(count, Allocator.Persistent),
                postionIndex = new NativeArray<int>(count, Allocator.Persistent),
                position = new NativeArray<float3>(count, Allocator.Persistent),
                forward = new NativeArray<float3>(count, Allocator.Persistent),
                direction = new NativeArray<int>(count, Allocator.Persistent),
                targetForward = new NativeArray<float3>(count, Allocator.Persistent),
                targetDirection = new NativeArray<int>(count, Allocator.Persistent),
                animSpriteIndex = new NativeArray<int>(count, Allocator.Persistent),
                shadowSpriteIndex = new NativeArray<int>(count, Allocator.Persistent),
                animSpriteData = new NativeArray<ChildToSpriteData>(count, Allocator.Persistent),
                animPSIndex = new NativeArray<int>(count, Allocator.Persistent),
                shadowPSIndex = new NativeArray<int>(count, Allocator.Persistent),
                state = new NativeArray<int>(count, Allocator.Persistent),
                subState = new NativeArray<int>(count, Allocator.Persistent),
                soldierType = new NativeArray<int>(count, Allocator.Persistent),
                soldierId = new NativeArray<int>(count, Allocator.Persistent),
                alpha = new NativeArray<float>(count, Allocator.Persistent),
                startMovePosition = new NativeArray<float3>(count, Allocator.Persistent),
                targetMovePosition = new NativeArray<float3>(count, Allocator.Persistent),
                childTargetPosition = new NativeArray<float3>(count, Allocator.Persistent),
                moveNeedTime = new NativeArray<float>(count, Allocator.Persistent),
                moveStartTime = new NativeArray<float>(count, Allocator.Persistent),
                rotateStartTime = new NativeArray<float>(count, Allocator.Persistent),
                InAdjustPositionState = new NativeArray<bool>(count, Allocator.Persistent),
                IsFirstChange = new NativeArray<bool>(count, Allocator.Persistent),
                stageStartTime = new NativeArray<float>(count, Allocator.Persistent),
                instructionSetIndex = new NativeArray<int>(count, Allocator.Persistent),
                waitTime = new NativeArray<float>(count, Allocator.Persistent),
                actionIndex = new NativeArray<int>(count, Allocator.Persistent),
                actionConfigId = new NativeArray<int>(count, Allocator.Persistent),
                transformOffset = new NativeArray<float3>(count, Allocator.Persistent),
                //movementData = new NativeArray<ChildMovementData>(count,Allocator.Persistent),
            };
        }

        public void Initialize()
        {
            _isDisposed = false;
            Reset();
            updateState = 0;

            marchNativeData = CreateMarchNativeData(marchNativeArrayLength);
            childNativeData = CreateChildNativeData(childNativeArrayLength);
            animSprites = new List<AnimSprite>(MAX_CHILD_COUNT);
            //shadowSprites = new List<AnimSprite>(MAX_CHILD_COUNT);
            for (int i = 0; i < MAX_CHILD_COUNT; i++)
            {
                animSprites.Add(null);
                //shadowSprites.Add(null);
            }

            random = new Random();
            random.InitState();

            var angle = -5.625f;
            directions = new NativeArray<float3>(32, Allocator.Persistent);
            for (int i = 0; i < 32; i++)
            {
                var fixedForward = Quaternion.AngleAxis(angle + 5.625f, Vector3.up) * Vector3.forward;
                directions[i] = fixedForward;
                angle += 11.25f;
            }


            crossingGateDataPool.Clear();
            //先初始化10个
            for (int i = 0; i < 10; i++)
            {
                crossingGateDataPool.Add(new CrossingGateFormationData());
            }
            
            
            isDebug = LocalPrefs.GetInt("SquareDataManagerDebug") == 1;
            if (isDebug)
            {
                InitDebug();
            }
        }

        public void InitSoldierIndex()
        {
            var resMgr = ArmyManager.Instance.GetRtsResourceManager();
            var soldierIndexConfig = resMgr.Rts_formation_soldierIndexConfig;
            var count = soldierIndexConfig.Count;
            var maxCount = count * (1 + 17) * 17 / 2;
            soldierPositionIndexNativeArrays = new NativeArray<int>(maxCount,Allocator.Persistent);
            var list = new List<int>();

            var enumator = soldierIndexConfig.GetEnumerator();
            while (enumator.MoveNext())
            {
                var key = enumator.Current.Key;
                var value = enumator.Current.Value;
                foreach (var dic in value)
                {
                    foreach (var index in dic.Value.soldierLocation)
                    {
                        list.Add(index);
                    }
                }
            }
            for (int i = 0; i < list.Count; i++)
            {
                soldierPositionIndexNativeArrays[i] = list[i];
            }
            enumator.Dispose();
        }
        public void InitSpriteData(List<List<CreatorVisitor>> creators)
        {
            if (!Enabled)
            {
                return;
            }

            var list = new List<CreatorVisitor>();
            for (int i = 0; i < creators.Count; i++)
            {
                for (int j = 0; j < creators[i].Count; j++)
                {
                    list.Add(creators[i][j]);
                }
            }

            //animSpriteData = new NativeList<AnimSpriteData>(list.Count, Allocator.Persistent);
            spriteNameToPSIndexDic = new Dictionary<string, int>();
            psIndexToSpriteNameDic = new Dictionary<int, string>();
            animSpriteData = new List<AnimSpriteData>();
            for (int i = 0; i < list.Count; i++)
            {
                var creatorName = list[i].CreatorName;
                spriteNameToPSIndexDic[creatorName] = i;
                psIndexToSpriteNameDic[i] = creatorName;
                var data = list[i].GetData();
                animSpriteData.Add(new AnimSpriteData
                {
                    actions = data.actions,
                    alphas = data.alphas,
                    offsets = data.offsets,
                    positions = data.positions,
                    removes = data.removes,
                    restarts = data.restarts,
                    rotations = data.rotations,
                    speeds = data.speeds,
                    spriteSizes = data.spriteSizes,
                    count = data.actions.Length,
                    team = data.team,
                    childIndex = new NativeArray<int>(data.actions.Length, Allocator.Persistent),
                    valid = new NativeArray<bool>(data.actions.Length, Allocator.Persistent),
                    isShadow = new NativeArray<bool>(data.actions.Length, Allocator.Persistent),
                    createScale = ArmyManager.GetSoldierSpriteCreatorScale(creatorName),
                });
            }

            spriteDataReady = true;
        }

        private void InitSpriteData(CreatorVisitor creator)
        {
            if (spriteNameToPSIndexDic == null)
            {
                spriteNameToPSIndexDic = new Dictionary<string, int>();
            }

            if (animSpriteData == null)
            {
                animSpriteData = new List<AnimSpriteData>();
            }

            if (!spriteNameToPSIndexDic.ContainsKey(creator.CreatorName))
            {
                var data = creator.GetData();
                animSpriteData.Add(new AnimSpriteData
                {
                    actions = data.actions,
                    alphas = data.alphas,
                    offsets = data.offsets,
                    positions = data.positions,
                    removes = data.removes,
                    restarts = data.restarts,
                    rotations = data.rotations,
                    speeds = data.speeds,
                    spriteSizes = data.spriteSizes,
                    count = data.actions.Length,
                    team = data.team,
                    childIndex = new NativeArray<int>(data.actions.Length, Allocator.Persistent),
                    valid = new NativeArray<bool>(data.actions.Length, Allocator.Persistent),
                    isShadow = new NativeArray<bool>(data.actions.Length, Allocator.Persistent),
                    createScale = ArmyManager.GetSoldierSpriteCreatorScale(creator.CreatorName),
                });
                spriteNameToPSIndexDic[creator.CreatorName] = animSpriteData.Count - 1;
                psIndexToSpriteNameDic[animSpriteData.Count - 1] = creator.CreatorName;
            }
        }
        public void OnSpriteCreatorArrayChanged(string creatorName, AnimSpriteCreatorData data)
        {
            var index = spriteNameToPSIndexDic[creatorName];
            var animSpriteData = this.animSpriteData[index];
            animSpriteData.actions = data.actions;
            animSpriteData.alphas = data.alphas;
            animSpriteData.offsets = data.offsets;
            animSpriteData.positions = data.positions;
            animSpriteData.removes = data.removes;
            animSpriteData.restarts = data.restarts;
            animSpriteData.rotations = data.rotations;
            animSpriteData.speeds = data.speeds;
            animSpriteData.spriteSizes = data.spriteSizes;
            animSpriteData.team = data.team;
            var newLength = data.actions.Length;
            animSpriteData.count = newLength;
            animSpriteData.childIndex = BattleUtils.GetExpendedArray(animSpriteData.childIndex, newLength);
            animSpriteData.valid = BattleUtils.GetExpendedArray(animSpriteData.valid, newLength);
            animSpriteData.isShadow = BattleUtils.GetExpendedArray(animSpriteData.isShadow, newLength);
            this.animSpriteData[index] = animSpriteData;

        }

        public void UpdateSpriteCreatorScale(string creatorName, float scale)
        {
            if (spriteNameToPSIndexDic.TryGetValue(creatorName, out var i))
            {
                var data = animSpriteData[i];
                data.createScale = scale;
                animSpriteData[i] = data;
            }
        }
        private Dictionary<string, Dictionary<int, string>> spriteNameDic =
            new Dictionary<string, Dictionary<int, string>>();

        private const string shadowSpriteCreatorName = "shadow0";
        private const string shadowSpriteName = "shadow";

        private string GetSpriteNameByModelNameAndTeam(string modelName, int team)
        {
            if (!spriteNameDic.TryGetValue(modelName, out var spriteNames))
            {
                spriteNames = new Dictionary<int, string>();
                spriteNameDic[modelName] = spriteNames;
            }

            if (!spriteNames.TryGetValue(team, out var name))
            {
                name = modelName + team;
                spriteNames[team] = name;
            }

            return name;
        }

        private void InitChildSprite(int index, string modelName, int team,float positionScale, bool createShadow = true)
        {
            //Profiler.BeginSample("InitChildSprite");
     
            //Profiler.EndSample();
            //Profiler.BeginSample("SquareDataManager.InitChildSprite.GetSoldierSprite");
            var creator = ArmyManager.GetSpriteCreatorByOriginNameAndTeam(modelName, 0);
            if (creator != null)
            {
                var cv = creator as CreatorVisitor;
                InitSpriteData(cv);
                CreateSpriteData(index, creator, modelName,team,positionScale);
                if (!soldierAtlasMap.ContainsKey(modelName))
                {
                    soldierAtlasMap.Add(modelName, new SoldierAtlasLoader
                    {
                        creator = cv,
                    });
                }
            }
            else
            {
                var action = new Action<CreatorVisitor>((cv) =>
                {
                    CreateSpriteData(index, cv, modelName, team, positionScale);
                });
                loadSoldierAtlasCallBackMap[index] = action;
                ArmyManager.LoadAndCreateSoldierSprite(modelName, 0, (loadedCreator) =>
                {
                    //回调回来时管理器已经销毁
                    if (_isDisposed)
                    {
                        return;
                    }
                    var cv = loadedCreator as CreatorVisitor;
                    InitSpriteData(cv);
                    //回调回来时需要判断之前的存的回调是否相同，如果不同则说明那个方阵已经无效了
                    if (loadSoldierAtlasCallBackMap.TryGetValue(index, out var callBack))
                    {
                        if (callBack == action)
                        {
                            action.Invoke(cv);
                            loadSoldierAtlasCallBackMap.Remove(index);
                        }
                    }
                    if (!soldierAtlasMap.ContainsKey(modelName))
                    {
                        soldierAtlasMap.Add(modelName, new SoldierAtlasLoader
                        {
                            creator = cv,
                        });
                    }
                });
            }
            
            //Profiler.EndSample();
            
            //Profiler.EndSample();
        }

        private void CreateSpriteData(int index, AnimSpriteCreator creator, string modelName, int team,float positionScale)
        {
            var rtsResManager = ArmyManager.Instance.GetRtsResourceManager();
            //Profiler.BeginSample("SquareDataManager.InitChildSprite.String1");
            var spriteName = GetSpriteNameByModelNameAndTeam(modelName, 0);
            AnimSprite sprite = ArmyManager.GetSoldierSprite(creator);
            var animSprite = childNativeData.animSpriteData[index];
            animSprite.visible = true;
            var configSpeed = rtsResManager.GetActionSpeedByName(modelName);

            if (sprite != null)
            {
                var psIndex = spriteNameToPSIndexDic[spriteName];
                var data = animSpriteData[psIndex];
                var scale = rtsResManager.GetModelScaleByName(modelName) * animSpriteScale * positionScale ;
                var offsetY = rtsResManager.GetModelYOffsetByName(modelName);
                sprite.spriteSize = scale;    /** data.createScale; // USE_PARTICLE_SYSTEM */
                sprite.alpha = childNativeData.alpha[index];
                
                childNativeData.animSpriteIndex[index] = sprite.spriteIndex;
                animSprite.spriteOriginScale = scale;
                //Debug.LogError(modelName + " " + index + " " + scale + " " + rtsResManager.GetModelScaleByName(modelName) + " " + positionScale + " " + animSpriteScale);
                animSprite.spriteYOffset = offsetY;
                animSprite.alpha = sprite.alpha;
                animSprite.animationSpeed = 1;
                animSprite.configSpeed = configSpeed;
                animSprite.team = team;
                childNativeData.animPSIndex[index] = psIndex;
                if (data.childIndex[sprite.spriteIndex] > 0)
                {
                    Debug.LogError(data.childIndex[sprite.spriteIndex] + "被重复使用了，spriteIndex:" + sprite.spriteIndex + " modelName:" + modelName);
                }

                data.childIndex[sprite.spriteIndex] = index;
                //Debug.LogError("创建小兵 childIndex = " + index + " spriteIndex = " + sprite.spriteIndex);
                data.valid[sprite.spriteIndex] = true;
                data.isShadow[sprite.spriteIndex] = false;
                data.team[sprite.spriteIndex] = team;
                //data.spriteSizes[sprite.spriteIndex] = 0;
                animSprites[index] = sprite;
            }
            else
            {
                if (ArmyManager.IsDebugSpriteLoading)
                {
                    MarchHelper.Log("CreateSpriteData时 "+modelName+"找不到");
                }
            }

            childNativeData.animSpriteData[index] = animSprite;
        }

        public void InitSquare(int index, long marchId,TargetCoordinateType targetCoordinateType, List<int> soldierIdList, bool isMonster, bool isEscape,int team,List<SoldierLocation> formationPos)
        {
#if UNITY_EDITOR
            //Profiler.BeginSample("InitSquare.TryParse");
            long _mid = marchId;
            //Profiler.EndSample();
#endif
            //Debug.LogError("方阵初始化成功 " + index);
            var childCount = soldierIdList.Count;
            //从右到左按位取，值变了就说明兵种类型变了，比如步步骑骑骑骑 = 00000000000000000000000000111100
            uint soldierTypeList = 0;
            //初始化小兵
            var childHead = GetNewChild(childCount);
            if (childHead >= 0)
            {
                //int team = ;
                marchNativeData.team[index] = team;
                marchNativeData.childCount[index] = childCount;
                marchNativeData.childIndexHead[index] = childHead;

                uint type = 1;
                string soldierName = string.Empty;
                for (int i = 0; i < childCount; i++)
                {

                    var j = childHead + i;
                    var soldierId = soldierIdList[i];
                    var soldierType = BattleFormationHelper.GetSoldierType(soldierId, UnitType.Soldier);
                    if (isMonster)
                    {
                        soldierType += 100;
                    }

                    string modelName;
                    if (RTSQualityHelper.IsSimpleMode && (RTSQualityHelper.Quality == 0 || RTSQualityHelper.Quality == 1))
                    {
                        if (isMonster)
                        {
                            modelName = BattleUtils.GetSoldierModelNameById(412011);
                        }
                        else
                        {
                            modelName = BattleUtils.GetLowQualitySoldierModelName(soldierId,1);//临时写死成1
//                            modelName = BattleUtils.GetLowQualitySoldierModelName(soldierId,soldierType);
                        }
                    }
                    else
                    {
                        modelName = BattleUtils.GetSoldierModelNameById(soldierId);
                    }
                    if (string.IsNullOrEmpty(modelName))
                    {
                        Debug.LogErrorFormat(LogModule.RTS, "获取兵种序列帧出错：soldierId {0}   检查阵型配表formationType={1} 是否有错",
                            new object[] {soldierId, marchNativeData.formationId[index]});
                        //modelName = BattleUtils.AmbulanceSoldierName;
                    }

                    var positionScale = GetPositionScale(formationPos, i);
                    InitChildSprite(j, modelName, team,positionScale);
                    childNativeData.soldierType[j] = soldierType;
                    childNativeData.soldierId[j] = soldierId;
                    if (!attackActionConfigData.ContainsKey(soldierType))
                    {
                        //UnityEngine.Debug.LogError("找不到士兵的攻击配表"+soldierType);
                        childNativeData.actionConfigId[j] = 1;
                    }
                    else
                    {
                        childNativeData.actionConfigId[j] = soldierType;
                    }

                    childNativeData.moveNeedTime[j] = 0;
                    if (soldierName != modelName)
                    {
                        soldierName = modelName;
                        type = 1 - type;
                    }

                    soldierTypeList += type << i;
                }
            }

            marchNativeData.soldierTypeList[index] = soldierTypeList;
            marchNativeData.needForceMoveChildren[index] = true;
            marchNativeData.changeStatusFlag[index] = true;
            marchNativeData.isEscape[index] = isEscape;

#if UNITY_EDITOR
            if (isDebug)
            {
                if (squares.Count <= index)
                {
                    var trans = AddDebugSquare(index, marchId,targetCoordinateType);
                    squares.Add(trans);
                }
                else if (squares[index] == null)
                {
                    var trans = AddDebugSquare(index, marchId,targetCoordinateType);
                    squares[index] = trans;
                }

                for (int i = 0; i < childCount; i++)
                {
                    var j = childHead + i;
                    if (children[j] == null)
                    {
                        AddDebugChildren(j);
                    }

                    children[j].transform.SetParent(squares[index]);
                }
            }
#endif
        }

        public void AddRecoverSquareToList(int index)
        {
            recoverSquareList.Add(index);
        }

        public void RecoverSquareAsync(int index)
        {
            AddRecoverSquareToList(index);
        }
        private List<AnimSprite> waitDeleSpriteList = new List<AnimSprite>();

        private void RemoveSprite()
        {
            if (waitDeleSpriteList.Count > 0)
            {
                for (int i = waitDeleSpriteList.Count - 1; i >= 0; i--)
                {
                    var animSprite = waitDeleSpriteList[i];
                    var oldIndex = animSprite.spriteIndex;
                    var changedIndexSprite = ArmyManager.RemoveSprite(animSprite);
                    if (animSprite.psIndex >= 0 && animSprite.psIndex < animSpriteData.Count)
                    {
                        var data = animSpriteData[animSprite.psIndex];
                        //交换数据
                        if (changedIndexSprite >= 0)
                        {
                            var child = data.childIndex[changedIndexSprite];
                            if (child >= 0 && changedIndexSprite != oldIndex)//因为有可能这个animsprite并不是和child对应的，比如死亡抛飞的animsprite
                            {
                                data.childIndex[oldIndex] = child;
                                data.valid[oldIndex] = true;
                                //data.restarts[oldIndex] = true;
                                childNativeData.animSpriteIndex[child] = oldIndex;
                            }
                            else
                            {
                                data.childIndex[oldIndex] = -1;
                                data.valid[oldIndex] = false;
                                data.restarts[oldIndex] = true;
                            }
                            //Debug.LogError("移除小兵 childIndex = " + child + " old = " + oldIndex + " change = " + changedIndexSprite);
                            data.childIndex[changedIndexSprite] = -1;
                            data.valid[changedIndexSprite] = false;
                        }
                        else
                        {
                            data.childIndex[oldIndex] = -1;
                            data.valid[oldIndex] = false;
                            Debug.LogError("精灵移除失败");
                        }
                        animSprite.psIndex = -1;
                    }
                }
                waitDeleSpriteList.Clear();
            }
        }

        //移除序列帧小兵唯一接口
        private void RemoveSprite(AnimSprite animSprite,int psIndex)
        {
            animSprite.psIndex = psIndex;
            waitDeleSpriteList.Add(animSprite);
        }

        private void RemoveAnimSprite(int i)
        {
            var animSprite = animSprites[i];
            if (animSprite != null)
            {
                var psIndex = childNativeData.animPSIndex[i];
                RemoveSprite(animSprite, psIndex);
                animSprites[i] = null;
                childNativeData.animSpriteIndex[i] = -1;
            }
            else
            {
                //Debug.LogError("精灵移除失败"+i);
            }
        }

        private void RemoveShadowSprite(int i)
        {
            //var shadow = shadowSprites[i];
            //if (shadow != null)
            //{
            //    var psIndex = childNativeData.shadowPSIndex[i];
            //    var data = animSpriteData[psIndex];
            //    var oldIndex = shadow.spriteIndex;
            //    var changedIndexSprite = ArmyManager.RemoveSprite(shadow);
            //    //交换数据
            //    if (changedIndexSprite >= 0)
            //    {
            //        var child = data.childIndex[changedIndexSprite];
            //        if (changedIndexSprite != oldIndex)
            //        {
            //            data.childIndex[oldIndex] = child;
            //            data.restarts[oldIndex] = true;
            //        }
            //        else
            //        {
            //            data.childIndex[oldIndex] = -1;
            //            data.valid[oldIndex] = false;
            //        }

            //        childNativeData.shadowSpriteIndex[child] = oldIndex;
            //    }
            //    else
            //    {
            //        data.childIndex[oldIndex] = -1;
            //        data.valid[oldIndex] = false;
            //    }

            //    data.childIndex[changedIndexSprite] = -1;
            //    data.valid[changedIndexSprite] = false;
            //    shadowSprites[i] = null;
            //    childNativeData.shadowSpriteIndex[i] = -1;
            //}
        }

        public void RecoverSquare(int index)
        {
            if (index < 0)
            {
                return;
            }

            int head;
            int childCount;
            if (index >= marchNativeData.count || !marchNativeData.valid[index])
            {
                return;
            }
#if UNITY_EDITOR
            marchNativeData.marchId[index] = 0;
#endif

            marchNativeData.valid[index] = false;
            marchNativeData.changeStatusFlag[index] = false;
            head = marchNativeData.childIndexHead[index];
            childCount = marchNativeData.childCount[index];
            for (int i = head; i < head + childCount; i++)
            {
                if (childNativeData.valid[i])
                {
                    RemoveAnimSprite(i);
                }

                RemoveShadowSprite(i);
                childNativeData.state[i] = 0;
                childNativeData.valid[i] = false;
                TryRemoveSoldierAtlasCallback(i);
            }

            if (freeIndexDictionary.TryGetValue(childCount,out var stack))
            {
                stack.Push(head);
            }
#if UNITY_EDITOR
            if (isDebug)
            {
                for (int i = head; i < head + childCount; i++)
                {
                    if (children[i] != null)
                    {
                        GameObject.Destroy(children[i].gameObject);
                        children[i] = null;
                    }
                }

                if (squares[index] != null)
                {
                    GameObject.Destroy(squares[index].gameObject);
                    squares[index] = null;
                }
            }
#endif
        }

        public int GetNewSquare()
        {
            for (int i = 0; i < marchNativeData.count; i++)
            {
                var index = (currentMarchIndex + i) % marchNativeData.count;
                if (!marchNativeData.valid[index])
                {
                    marchNativeData.valid[index] = true;
                    marchNativeData.index[index] = index;
                    currentMarchIndex = index + 1;
                    return index;
                }
            }

            //先检查是否需要扩容
            var oldMarchNativeArrayLength = marchNativeArrayLength;
            if (marchNativeArrayLength < MAX_MARCH_COUNT)
            {
                ExpandMarchNativeArray();
                var index = oldMarchNativeArrayLength;
                marchNativeData.valid[index] = true;
                marchNativeData.index[index] = index;
                currentMarchIndex = index + 1;
                return index;
            }

            Debug.LogError("方阵已经用完了");
            return -1;
        }
        Dictionary<int, Stack<int>> freeIndexDictionary = new Dictionary<int, Stack<int>>();

        public int GetNewChild(int childCount)
        {
            int childIndexStart = 0;
            bool isCachedIndex = false;
            if (freeIndexDictionary.TryGetValue(childCount,out var statck))
            {
                if (statck.Count > 0)
                {
                    childIndexStart = statck.Pop();
                    isCachedIndex = true;
                }
                else
                {
                    childIndexStart = currentChildIndex;
                }
            }
            else
            {
                childIndexStart = currentChildIndex;
            }

            for (int i = childIndexStart; i < childNativeData.count - childCount; i++)
            {
                int latestUsingIndex = -1;
                for (int j = 0; j < childCount; j++)
                {
                    var idx = j + i;
                    //if (idx < childNativeData.count)
                    //{
                        if (childNativeData.valid[idx])
                        {
                            latestUsingIndex = idx + 1;
                            break;
                        }
                    //}
                }

                if (latestUsingIndex >= 0)
                {
                    i = latestUsingIndex;
                    continue;
                }
                else
                {
                    for (int j = 0; j < childCount; j++)
                    {
                        var idx = j + i;
                        //if (idx < childNativeData.count)
                        //{
                            childNativeData.index[idx] = j;
                        childNativeData.postionIndex[idx] = j;
                            childNativeData.state[idx] = 0;
                            childNativeData.subState[idx] = 0;
                            childNativeData.valid[idx] = true;
                            childNativeData.alpha[idx] = 1;
                        //}
                    }
                    if (!isCachedIndex)
                    {
                        currentChildIndex += childCount;
                    }
                    return i;
                }
            }

            //先检查是否需要扩容
            var oldChildNativeArrayLength = childNativeArrayLength;
            if (childNativeArrayLength < MAX_CHILD_COUNT)
            {
                ExpandChildNativeArray();
                if (childNativeArrayLength - oldChildNativeArrayLength >= childCount)
                {
                    var i = oldChildNativeArrayLength;
                    for (int j = 0; j < childCount; j++)
                    {
                        var idx = j + i;
                        //if (idx < childNativeData.count)
                        //{
                        childNativeData.index[idx] = j;
                        childNativeData.postionIndex[idx] = j;
                        childNativeData.state[idx] = 0;
                        childNativeData.subState[idx] = 0;
                        childNativeData.valid[idx] = true;
                        //}

                    }
                    if (!isCachedIndex)
                    {
                        currentChildIndex += childCount;
                    }
                    return i;
                }
            }

            Debug.LogError("小兵已经用完了");
            return -1;
        }


        public void SetStartPosition(int index, Vector3 position)
        {
            if (index < 0)
            {
                return;
            }

            marchNativeData.squareStartPosition[index] = position;
        }

        public void SetEndPosition(int index, Vector3 position)
        {
            if (index < 0)
            {
                return;
            }

            marchNativeData.squareEndPosition[index] = position;
        }

        public void SetSegmentStartTime(int index, float startTime)
        {
            if (index < 0)
            {
                return;
            }

            marchNativeData.segmentStartTime[index] = startTime;
        }

        public void SetClientInBattle(int index, bool isInBattle)
        {
            if (index < 0)
            {
                return;
            }

            if (isInBattle != marchNativeData.isClientInBattle[index])
            {
                marchNativeData.changeStatusFlag[index] = true;
                if (!isInBattle)
                {
                    marchNativeData.isServerPosChange[index] = true;
                }
                marchNativeData.isClientInBattle[index] = isInBattle;
            }
        }

        public void SetForward(int index, Vector3 forward, bool setChild = false,bool isNotScout = true)
        {
            if (index < 0)
            {
                return;
            }
            //判断镜像
            //镜像
            bool isServerPosChange = false;
            var currentForward = marchNativeData.forward[index];
            if (!forward.Equals(Vector3.zero))
            {
                bool isFirstChanged = false;
                if (currentForward.Equals(Vector3.zero))
                {
                    currentForward = forward;
                    isFirstChanged = true;
                }
                var angle = PveUtils.GetAngle(currentForward, forward);
                var last = marchNativeData.TurnState[index];
                var current = 0;
                if (angle <= 45 && angle > -45)
                {
                    current = 0;
                }
                else if (angle >= 45 && angle < 135)
                {
                    current = 3;
                }
                else if (angle >= 135 && angle <= 180 || angle >= -180 && angle < -135)
                {
                    current = 2;
                }
                else if (angle <= -45 && angle >= -135)
                {
                    current = 1;
                }

                bool posChanged = true;
                if (last != 0 && current == 0)//上次变阵且这次角度在45度内 不触发变阵
                {
                    posChanged = false;
                }

                float3 float3forward = forward;
                if (isNotScout && (!Mathf.Approximately(currentForward.x, float3forward.x) && !Mathf.Approximately(currentForward.z, float3forward.z) && posChanged || isFirstChanged)) //原地转向
                {
                    marchNativeData.TurnState[index] = current;
                    marchNativeData.isServerPosChange[index] = true;
                    marchNativeData.changeStatusFlag[index] = true;
                }
//                Debug.LogError("index:" + index + "    TurnState：" + marchNativeData.TurnState[index] +
//                               "IsPosChanged    " + marchNativeData.isServerPosChange[index] + "current:   " +
//                               current + "posChanged:     " + posChanged + "isFirstSet    " + isFirstSet  + "currentForward :   " + currentForward + "    forward " + forward + "        angle:    "+angle);
            }
            marchNativeData.forward[index] = forward;
        }

        public void SetPosition(int index, Vector3 position, bool forceMoveChildren = false)
        {
            if (index < 0)
            {
                return;
            }
            var lastPosition = marchNativeData.position[index];
            marchNativeData.position[index] = position;
            marchNativeData.isServerPosChange[index] = Vector3.Distance(lastPosition, position) > 0.1f; //TODO:每次设置的时候都要判断么？
            marchNativeData.needForceMoveChildren[index] = marchNativeData.needForceMoveChildren[index] || forceMoveChildren;
        }

        
        public void SetFomationIndexOffset(int index, int offset)
        {
            if (index < 0)
            {
                return;
            }

            marchNativeData.formationPositionIndexOffset[index] = offset;
        }

        public void SetIsServerPosChange(int index, bool change)
        {
            if (index < 0)
            {
                return;
            }

            marchNativeData.isServerPosChange[index] = change;
        }

        public void SetBesiege(int index, bool isBesiege)
        {
            if (index < 0)
            {
                return;
            }

            marchNativeData.isBesiege[index] = isBesiege;
        }

        public void SetAlpha(int index, float alpha)
        {
            if (index < 0)
            {
                return;
            }

            marchNativeData.alpha[index] = alpha;
            marchNativeData.overrideAlpha[index] = true;
            if (updateState == 0)
            {
                animSpriteDataChanged = true;
            }
        }

        public void SetTeam(int index, int team, bool isForceSet = false,List<SoldierLocation> formationPos = null)
        {
            if (index < 0)
            {
                return;
            }

            var oldTeam = marchNativeData.team[index];
            marchNativeData.team[index] = team;
            if (oldTeam != team && oldTeam >= 0 || isForceSet)
            {
                RefreshChildrenTeam(index, team,formationPos);
            }
            animSpriteDataChanged = true;
        }

        public void SetSpeed(int index, float speed)
        {
            if (index < 0)
            {
                return;
            }

            marchNativeData.speed[index] = speed;
        }

        public void SetSegmentDuration(int index, float duration)
        {
            if (index < 0)
            {
                return;
            }

            marchNativeData.currentSegmentDuration[index] = duration;
        }

        public void SetFormationId(int index, int formationType, int soldierCount)
        {
            if (index < 0)
            {
                return;
            }

            var formationId = CalculateFormationId(formationType, soldierCount);
            marchNativeData.formationId[index] = formationId;
        }

        public void SetSoldierNum(int index, int initSoldierNum, int currentSoldierNum)
        {
            if (index < 0)
            {
                return;
            }

            //现在不死并
            /*if (currentSoldierNum > 0)
            {
                return;
            }
            marchNativeData.initSoldierNum[index] = initSoldierNum;
            marchNativeData.curSoldierNum[index] = currentSoldierNum;
            var soldierType = marchNativeData.soldierTypeList[index];
            var soldierCount = marchNativeData.childCount[index];
            var l = GetSoldierModelCount(soldierType, soldierCount);
            
            var percent = (float) currentSoldierNum / initSoldierNum;
            int soldierTypeIndex = 0;
            int currentModelCount = 0;
            int head = marchNativeData.childIndexHead[index];
            for (int i = 0; i < soldierCount; i++)
            {
                var total = l[soldierTypeIndex];
                var alive =  Mathf.CeilToInt( total * percent);
                currentModelCount++;
                

                if (currentModelCount > alive && childNativeData.state[head + i] != 4)
                {
                    childNativeData.state[head + i] = 3;
                }
                if (currentModelCount >= total)
                {
                    soldierTypeIndex++;
                    currentModelCount = 0;
                }
            }*/
        }

        private void RefreshChildrenTeam(int index, int team,List<SoldierLocation> formationPos)
        {
            //把原来的小兵删了，新建另一个阵营的小兵
            var childHead = marchNativeData.childIndexHead[index];
            var childCount = marchNativeData.childCount[index];
            if (freeIndexDictionary.TryGetValue(childCount, out var stack))
            {
                stack.Push(childHead);
            }
            for (int i = childHead; i < childHead + childCount; i++)
            {
                var soldierId = childNativeData.soldierId[i];
                var modelName = BattleUtils.GetSoldierModelNameById(soldierId);
                //删除以前的小兵
                RemoveAnimSprite(i);
                var positionScale = GetPositionScale(formationPos, i - childHead);
                InitChildSprite(i, modelName, team, positionScale,false);
            }
        }

        private float GetPositionScale(List<SoldierLocation> formationPos,int formationIndex)
        {
            if (formationPos != null && formationPos.Count > formationIndex)
            {
                return formationPos[formationIndex].scale;
            }
            return 1;
        }

        //key 士兵id value 加减
        public void UpdateChildDeadOrReborn(int index, Dictionary<int, int> changedList, bool isForce = false)
        {
            if (index < 0)
            {
                return;
            }

            int head = marchNativeData.childIndexHead[index];
            int soldierCount = marchNativeData.childCount[index];
            for (int i = head; i < head + soldierCount; i++)
            {
                var soldierId = childNativeData.soldierId[i];
                if (changedList.TryGetValue(soldierId, out var change))
                {
                    if (change > 0)
                    {
                        //要活
                        /*if (childNativeData.state[i] == 4)
                        {
                            childNativeData.state[i] = 0;
                            childNativeData.
                        }*/
                    }
                    else if (change == 0)
                    {
                        changedList.Remove(soldierId);
                    }
                    else if (change < 0)
                    {
                        //要死
                        if (childNativeData.state[i] != 3 && childNativeData.state[i] != 4)
                        {
                            if (!isForce)
                            {
                                childNativeData.state[i] = 3; //Enum_ChildState_ReadyToDead
                            }
                            else
                            {
                                childNativeData.state[i] = 4; //Enum_ChildState_Dead
                                var animSprite = childNativeData.animSpriteData[i];
                                animSprite.visible = false;
                                childNativeData.animSpriteData[i] = animSprite;
                            }

                            change = change + 1;
                            changedList[soldierId] = change;
                        }
                    }
                }
            }
        }


        //返回不同兵种的模型类型
        private List<int> GetSoldierModelCount(uint soldierType, int count)
        {
            var l = new List<int>();
            uint lastT = 999;
            for (int i = 0; i < count; i++)
            {
                var t = (uint) ((soldierType & (1 << i)) >> i);
                if (t != lastT)
                {
                    l.Add(1);
                    lastT = t;
                }
                else
                {
                    l[l.Count - 1]++;
                }
            }

            return l;
        }

        /// <summary>
        /// 1 移动 2 进攻
        /// </summary>
        /// <param name="index"></param>
        /// <param name="status"></param>
        public void SetMarchStatus(int index, int status,bool needRefresh = true)
        {
            if (index < 0)
            {
                return;
            }

            marchNativeData.status[index] = status;
            marchNativeData.changeStatusFlag[index] = needRefresh;
        }

        public void SetEscape(int index, List<int> escapeSoldierId)
        {
            if (index < 0)
            {
                return;
            }

            if (!marchNativeData.isEscape[index])
            {
                marchNativeData.changeStatusFlag[index] = true;
                //删除现在的模型，变成救护车模型
                var team = marchNativeData.team[index];
                var childHead = marchNativeData.childIndexHead[index];
                var childCount = marchNativeData.childCount[index];

                for (int i = childHead; i < childHead + childCount; i++)
                {
                    //删除以前的小兵
                    RemoveAnimSprite(i);
                    var childIndex = i - childHead;
                    if (childIndex < escapeSoldierId.Count)
                    {
                        var soldierId = escapeSoldierId[childIndex];
                        childNativeData.soldierId[i] = soldierId;
                        var modelName = BattleUtils.GetSoldierModelNameById(soldierId);
                        var positionScale = GetPositionScale(formationPos, i - childHead);
                        InitChildSprite(i, modelName, team, positionScale,false);
                    }
                    else
                    {
                        RemoveShadowSprite(i);
                        childNativeData.valid[i] = false;
                        TryRemoveSoldierAtlasCallback(i);
                    }
                }

                marchNativeData.childCount[index] = escapeSoldierId.Count;
            }

            marchNativeData.isEscape[index] = true;
        }

        //public int ShowAmbulance(int index,Vector3 startForward)
        //{
        //    if (index < 0)
        //    {
        //        return -1;
        //    }
        //    var childHead = marchNativeData.childIndexHead[index];
        //    var childCount = marchNativeData.childCount[index];
        //    //创建一个救护车
        //    var position = (Vector3)marchNativeData.position[index] - /*Quaternion.AngleAxis(90,Vector3.up) * */startForward * 1f;
        //    var ambulanceData = new AmbulanceData();
        //    ambulanceData.position = position;
        //    var team = marchNativeData.team[index];
        //    if (team == 1)
        //    {
        //        team = 0;
        //    }
        //    if (team > 1)
        //    {
        //        team = 1;
        //    }
        //    ambulanceData.animSprite =
        //        ArmyManager.GetSoldierSprite(BattleUtils.AmbulanceSoldierName, team);
        //    ambulanceData.animSprite.offset = Vector3.zero;
        //    ambulanceData.initSize = ArmyManager.Instance.ResourceManager.GetModelScaleByName(BattleUtils.AmbulanceSoldierName) * animSpriteScale * 3;
        //    ambulanceData.animSprite.spriteSize = ambulanceData.initSize;
        //    ambulanceData.marchIndex = index;
        //    ambulanceData.animSprite.action = SPRITE_ACTION_ENUM.RUN;
        //    ambulanceData.startFadeTime = TimeUtils.GetClientTickTime();
        //    if (childCount > 0)
        //    {
        //        ambulanceData.childIndex = new List<int> {childHead,childHead + childCount - 1};
        //    }
        //    ambulanceList.Add(ambulanceData);
        //    return ambulanceList.Count - 1;
        //}

        private BattleFormationCfg GetBattleFormationConfigByFormationType(int formationType,int soldierCount)
        {
            BattleFormationCfg config = new BattleFormationCfg();
            if (formationIdDic.TryGetValue(formationType, out var list))
            {
                for (int i = 0; i < list.Count; i++)
                {
                    if (list[i].config.soldierNum >= soldierCount)
                    {
                        config = list[i].config;
                        break;
                    }
                }
            }
            return config;
        }

        private void ShowCrossingGateFormation(CrossingGateFormationData crossingGateData,BattleFormationCfg formationConfig,Vector3 startForward)
        {
            var sprites = crossingGateData.sprites;
            sprites.Clear();
            var offsets = crossingGateData.offsets;
            offsets.Clear();
            var psIndex = crossingGateData.psIndex;
            psIndex.Clear();
            for (int i = 0; i < formationConfig.soldierLocation.Count ; i++)
            {
                var soldierId = formationConfig.soldierLocation[i].id;
                var modelName = BattleUtils.GetSoldierModelNameById(soldierId);

                var creator = soldierAtlasMap[modelName].creator;
                var sprite = ArmyManager.GetSoldierSprite(creator);
                sprite.offset = Vector3.zero;
                sprite.spriteSize = ArmyManager.Instance.ResourceManager.GetModelScaleByName(modelName) *
                                    animSpriteScale;// * 3;
                sprite.team = crossingGateData.team;
                sprites.Add(sprite);
                var offset = formationConfig.soldierLocation[i].pos;
                offsets.Add(Quaternion.FromToRotation(Vector3.forward,startForward) * offset);
                sprite.rotation = startForward;
                sprite.action = SPRITE_ACTION_ENUM.RUN;
                sprite.NeedRefreshFlag = true;
                var index = spriteNameToPSIndexDic[GetSpriteNameByModelNameAndTeam(modelName, 0)];
                psIndex.Add(index);
                var d = animSpriteData[index];
                if (d.childIndex[sprite.spriteIndex] > 0)
                {
                    Debug.LogError("用到了已经使用的小兵 childIndex = " + d.childIndex[sprite.spriteIndex] + " spriteIndex = " + sprite.spriteIndex);
                }
                d.childIndex[sprite.spriteIndex] = -1;
            }
            
            crossingGateData.forward = startForward;
        }

        private class SoldierAtlasLoader
        {
            public string modelName;
            public int state;
            public CreatorVisitor creator;
            public List<Action> actions = new List<Action>();
        }
        
        private Dictionary<string, SoldierAtlasLoader> soldierAtlasMap = new Dictionary<string,SoldierAtlasLoader>();
        
        private void CheckSoldierAtlasReady(BattleFormationCfg config,Action loadOver)
        {
            int notReadyCount = 0;
            for (int i = 0; i < config.soldierLocation.Count; i++)
            {
                var soldierId = config.soldierLocation[i].id;
                var modelName = BattleUtils.GetSoldierModelNameById(soldierId);
                //已经有资源
                if (soldierAtlasMap.TryGetValue(modelName,out var loader))
                {
                    if (loader.state == 0)
                    {
                        loader.actions.Add(loadOver);
                    }
                }
                else
                {
                    //没有资源或还没注册
                    var state = 0;
                    loader = new SoldierAtlasLoader
                    {
                        state = 0,
                        modelName = modelName,
                    };
                    var creator = ArmyManager.GetSpriteCreatorByOriginNameAndTeam(modelName, 0);
                    if (creator != null)
                    {
                        //有资源但没注册
                        loader.state = 1;
                        var cv = creator as CreatorVisitor;
                        InitSpriteData(cv);
                        loader.creator = cv;
                    }
                    else
                    {
                        //没资源
                        notReadyCount++;
                        loader.actions.Add(loadOver);
                        ArmyManager.LoadAndCreateSoldierSprite(modelName, 0, (loadedCreator) =>
                        {
                            var cv = loadedCreator as CreatorVisitor;
                            loader.creator = cv;
                            InitSpriteData(cv);
                            notReadyCount--;
                            if (notReadyCount == 0)
                            {
                                for (int j = 0; j < loader.actions.Count; j++)
                                {
                                    loader.actions[j].Invoke();
                                }
                                loader.actions.Clear();
                            }
                        });
                    }
                    soldierAtlasMap.Add(modelName,loader);
                    
                }
            }

            if (notReadyCount == 0)
            {
                loadOver.Invoke();
            }
        }

        private CrossingGateFormationData GetCrossingGateFormationData()
        {
            CrossingGateFormationData data = null;
            if (crossingGateDataPool.Count > 0)
            {
                data = crossingGateDataPool[crossingGateDataPool.Count - 1];
                crossingGateDataPool.RemoveAt(crossingGateDataPool.Count - 1);
            }
            else
            {
                data = new CrossingGateFormationData();
            }
            return data;
        }

        private void RecoverCrossingGateFormationData(CrossingGateFormationData data)
        {
            crossingGateDataPool.Add(data);
        }

        public int CreateCrossingGateFormation(int index,int formationType,Vector3 startForward)
        {
            if (index < 0)
            {
                return -1;
            }
            
            if (crossingGateList.TryGetValue(index, out var data))
            {
                //有数据残留，先清理
                RemoveCrossingGateFormation(index);
            }
            var crossingGateData = GetCrossingGateFormationData();
            var formationConfig = GetBattleFormationConfigByFormationType(formationType,0);
            crossingGateData.resReady = false;
            crossingGateData.valid = true;
            var team = marchNativeData.team[index];
            crossingGateData.team = team;
            CheckSoldierAtlasReady(formationConfig, () =>
            {
                if (crossingGateData.valid)
                {
                    ShowCrossingGateFormation(crossingGateData, formationConfig, startForward);
                    crossingGateData.resReady = true;
                }
            });
            crossingGateData.marchIndex = index;
            crossingGateList[index] = crossingGateData;
            return index;
        }

        public void RemoveCrossingGateFormation(int crossingGateIndex)
        {
            if (crossingGateList.TryGetValue(crossingGateIndex, out var data))
            {
                data.valid = false;
                if (data.resReady)
                {
                    for (int i = 0; i < data.sprites.Count; i++)
                    {
                        RemoveSprite(data.sprites[i],data.psIndex[i]);
                    }
                }

                RecoverCrossingGateFormationData(data);
                crossingGateList.Remove(crossingGateIndex);
            }
        }
        

        public void SetEscapeNew(int index,bool isAllDead = false)
        {
            if (index < 0)
            {
                return;
            }

            /*if (!marchNativeData.isEscape[index])
            {
                marchNativeData.isEscape[index] = true;
            }*/
            var childHead = marchNativeData.childIndexHead[index];
            var childCount = marchNativeData.childCount[index];
            
            for (int i = childHead; i < childHead + childCount; i++)
            {
                if (!isAllDead && (i == childHead || i == childHead + childCount - 1))
                {
                    childNativeData.state[i] = 1;
                }
                else
                {
                    childNativeData.state[i] = 5;
                    childNativeData.subState[i] = 0;
                }
            }
            
            marchNativeData.changeStatusFlag[index] = true;
        }

        public void PlayDeadAnim(int index)
        {
            if (index < 0)
            {
                return;
            }

            /*if (!marchNativeData.isEscape[index])
            {
                marchNativeData.isEscape[index] = true;
            }*/
            var childHead = marchNativeData.childIndexHead[index];
            var childCount = marchNativeData.childCount[index];

            for (int i = childHead; i < childHead + childCount; i++)
            {
                childNativeData.state[i] = 6;
            }

            marchNativeData.changeStatusFlag[index] = true;
        }
        public void SetEscapeWithoutAmbulance(int index, int survivalsCount)
        {
            if (index != -1 && !marchNativeData.isEscape[index])
            {
                marchNativeData.isEscape[index] = true;
                var childHead = marchNativeData.childIndexHead[index];
                var childCount = marchNativeData.childCount[index];
            
                for (int i = childHead; i < childHead + childCount; i++)
                {
                    if (survivalsCount > 0)
                    {
                        survivalsCount--;
                        childNativeData.state[i] = 1;
                    }
                    else
                    {
                        childNativeData.state[i] = 5;
                        childNativeData.subState[i] = 0;
                    }
                }
                marchNativeData.changeStatusFlag[index] = true;
            }
        }
        
        /// <summary>
        /// 强制刷新所有小兵，让其走状态改变逻辑：这个只在从后台切回来或者断线重连使用
        /// </summary>
        public void ForceSetMarchStatusAll()
        {
            if (marchNativeData.inited)
            {
                for (int i = 0; i < marchNativeData.count; i++)
                {
                    if (marchNativeData.valid[i])
                    {
                        marchNativeData.needForceMoveChildren[i] = true;
                        marchNativeData.changeStatusFlag[i] = true;
                    }
                }
            }
           
        }

        public void ForceUpdateFightingTroopStatus()
        {
            if (marchNativeData.inited)
            {
                for (int i = 0; i < marchNativeData.count; i++)
                {
                    if (marchNativeData.valid[i] && marchNativeData.status[i] == 2) //2 == Enum_MarchState_Attack
                    {
                        marchNativeData.changeStatusFlag[i] = true;
                    }
                }
            }
        }
        public void SetArmyVisible(int index, bool visible)
        {
            if (index < 0)
            {
                return;
            }

            if (marchNativeData.valid[index])
            {
                var head = marchNativeData.childIndexHead[index];
                var count = marchNativeData.childCount[index];
                for (int i = head; i < head + count; i++)
                {
                    var state = childNativeData.state[i];
                    if (state == 3 || state == 4 || state == 5)
                    {
                        visible = false;
                    }
                    var animSprite = childNativeData.animSpriteData[i];
                    animSprite.visible = visible;
                    childNativeData.animSpriteData[i] = animSprite;
                }
            }
            animSpriteDataChanged = true;
        }
        
        public void SetAmbulanceVisible(int ambulanceIndex, bool visible)
        {
            if (ambulanceIndex >= 0 && ambulanceList.Count > ambulanceIndex)
            {
                var data = ambulanceList[ambulanceIndex];
                data.animSprite.spriteSize = visible ? data.initSize : 0;
            }
        }
        
        private List<JobHandle> jobHandles = new List<JobHandle>();
        private List<AnimSpriteJob> animSpriteJobs = new List<AnimSpriteJob>();

        public bool SpriteNeedUpdate()
        {
            return updateState != 2 || animSpriteDataChanged;
        }
        
        public void WaitForAnimSpriteJobsComplete(string name)
        {
            if (spriteNameToPSIndexDic.TryGetValue(name, out var index))
            {
                jobHandles[index].Complete();
            }
        }

        public void LateUpdate()
        {
            if (!Enabled)
            {
                return;
            }
            animSpriteDataChanged = false;
        }

        private void ExecuteJob(float realTime)
        {
            if (!attackDataReady || !spriteDataReady)
            {
                return;
            }
            
            //Profiler.BeginSample("[C#]SquareDataManager.UpdateJob");
            SquareJob jobData = new SquareJob();
//#if UNITY_EDITOR
            jobData.frameCount = Time.frameCount;
//#endif
            jobData.marchData = marchNativeData;
            jobData.childData = childNativeData;
            jobData.attackActionConfigs = attackActionConfigData;
            jobData.attackActions = attackActionData;
            jobData.useActionIds = useActionIds;
            jobData.actionInfos = actionInfos;
            jobData.directions = directions;
//            jobData.SoldierPositionIndexArray = soldierPositionIndexNativeArray;
//            jobData.SoldierPositionIndexArray235to325 = soldierPositionIndexArray235to325;
//            jobData.SoldierPositionIndexArray135to180 = soldierPositionIndexArray135to180;
//            jobData.SoldierPositionIndexArray45To135Degree = soldierPositionIndexArray45To135Degree;
            jobData.SoldierPositionIndexArrays = soldierPositionIndexNativeArrays;
            jobData.normalPositions = localPositionsNative;
            jobData.battlePositions = battlePositionsNative;
            jobData.localPositionIndex = localPositionsNativeIndex;
            jobData.realTime = realTime;
            jobData.random = random;

            //jobData.animSpriteData = animSpriteData;
            JobHandle handle = jobData.Schedule(marchNativeData.count, 1);
            handle.Complete();
            //Profiler.EndSample();

            //Profiler.BeginSample("[C#]SquareDataManager.UpdateSprites");
            if (isSpriteJobs)
            {
                animSpriteJobs.Clear();
                for (int i = 0; i < animSpriteData.Count; i++)
                {
                    if (animSpriteJobs.Count <= i)
                    {
                        animSpriteJobs.Add(new AnimSpriteJob
                        {
                            childData = childNativeData,
                            ps = animSpriteData[i],
                        });
                    }
                    jobHandles.Add(animSpriteJobs[i].Schedule());
                    //handle2.Complete();
                }

                for (int i = 0; i < jobHandles.Count; i++)
                {
                    jobHandles[i].Complete();
                }
                jobHandles.Clear();
            }
            /*else
            {
                for (int i = 0; i < childNativeData.count; i++)
                {
                    if (childNativeData.valid[i])
                    {
                        var data = childNativeData.animSpriteData[i];
                        var sprite = animSprites[i];
                        if (sprite != null)
                        {
                            sprite.position = data.position;
                            sprite.rotation = data.forward;
                            if (data.changeAnimationFlag)
                            {
                                sprite.action = (SPRITE_ACTION_ENUM)data.animationIndex;
                            }
                            if (data.changeAlphaFlag)
                            {
                                sprite.alpha = data.alpha;
                            }

                            sprite.speed = data.animationSpeed;
                        }

                        //var shadow = shadowSprites[i];
                        //if (shadow != null)
                        //{
                        //    shadow.position = data.position + data.shadowOffset;
                        //    if (data.changeAlphaFlag)
                        //    {
                        //        shadow.alpha = data.alpha;
                        //    }
                        //    shadow.speed = data.animationSpeed;
                        //}
                        data.changeAnimationFlag = false;
                        
                        childNativeData.animSpriteData[i] = data;
                    }
                }
            }*/
            //Profiler.EndSample();
        }


        private void UpdateFakeKnockBack()
        {
            var realTime = TimeUtils.GetClientTickTime();
            for (int i = 0; i < fakeKnockBackList.Count; i++)
            {
                var data = fakeKnockBackList[i];
                if (data.startFadeTime < 0)
                {
                    var startPosition = fakeKnockBackList[i].startPosition;
                    var knockBackHorizontalForward = fakeKnockBackList[i].startForward;
                    var passedTime = realTime - fakeKnockBackList[i].startKnockTime;
                    var verticalStartSpeed = fakeKnockBackList[i].verticalStartSpeed;
                    var verticalA = fakeKnockBackList[i].verticalA;
                    var horizontalDistance = fakeKnockBackList[i].horizontalDistance;
                    var vt = verticalStartSpeed + passedTime * verticalA;
                    var y = (vt * vt - verticalStartSpeed * verticalStartSpeed) / 2 / verticalA;
                    var totalTime = Math.Abs(verticalStartSpeed / (float)verticalA * 2);
                    if (passedTime >= totalTime)
                    {
                        passedTime = totalTime;
                        data.startFadeTime = realTime;
                        data.animSprite.action = SPRITE_ACTION_ENUM.DEAD;
                    }
                    var horizontalMove = passedTime / totalTime * horizontalDistance;
                    var newPosition = startPosition +
                                      horizontalMove * knockBackHorizontalForward.normalized +
                                      new Vector3(0, y, 0);
                    /*if (data.startFadeTime >= 0)
                    {
                        data.animSprite.position = newPosition + new Vector3(0,-0.01f,0);
                    }
                    else*/
                    {
                        data.animSprite.position = newPosition;
                    }
                    data.animSprite.rotation = -knockBackHorizontalForward;
                }
                else
                {
                    var fadeTime = 2;
                    var percent = (realTime - data.startFadeTime) / fadeTime;
                    if (percent<1)
                    {
                        data.animSprite.alpha = 1 - percent;
                    }
                    else
                    {
                        data.animSprite.alpha = 0;
                        data.animSprite.spriteSize = 0;
                        RemoveSprite(data.animSprite,data.psIndex);
                        fakeKnockBackList.RemoveAt(i);
                        i--;
                    }
                }
            }
        }

        private void UpdateCrossingGate(float time,float deltaTime)
        {
            foreach (var item in crossingGateList)
            {
                var data = item.Value;
                var key = item.Key;
                if (!data.resReady)
                {
                    continue;
                }
                if (!marchNativeData.valid[data.marchIndex])
                {
                    for (int j = 0; j < data.sprites.Count; j++)
                    {
                        ArmyManager.RemoveSprite(data.sprites[j]);
                    }
                    crossingGateDeleteList.Add(key);
                    continue;
                }
                var targetPosition = marchNativeData.position[data.marchIndex];
                for (int j = 0; j < data.sprites.Count; j++)
                {
                    var sprite = data.sprites[j];
                    sprite.alpha = 1;
                    sprite.position = new Vector3(targetPosition.x,0,targetPosition.z) + data.offsets[j];
                    //这两个赋值的原因是万一其他的小车被删除，会跟他替换位置，数据不会替换，因此需要每帧设置
                    sprite.rotation = data.forward;
                    sprite.team = data.team;
                }
            }

            if (crossingGateDeleteList.Count > 0)
            {
                for (int i = 0; i < crossingGateDeleteList.Count; i++)
                {
                    var key = crossingGateDeleteList[i];
                    if (crossingGateList.TryGetValue(key, out var data))
                    { 
                        RecoverCrossingGateFormationData(data);
                        crossingGateList.Remove(key);
                    }
               
                }
                crossingGateDeleteList.Clear();
            }
        }
        
        private void UpdateAmbulance(float time,float deltaTime)
        {
            for (int i = 0; i < ambulanceList.Count; i++)
            {
                var data = ambulanceList[i];
                if (!marchNativeData.valid[data.marchIndex])
                {
                    ArmyManager.RemoveSprite(data.animSprite);
                    ambulanceList.RemoveAt(i);
                    i--;
                    continue;
                }

                var targetPosition = marchNativeData.position[data.marchIndex];
                /*if (data.childIndex != null)
                {
                    targetPosition = childNativeData.position[data.childIndex[0]];
                }*/
                
                var rotation = Vector3.right;
                var squarePosition = marchNativeData.position[data.marchIndex];
                var squareForward = marchNativeData.forward[data.marchIndex];
                if (data.state == 0 && data.childIndex != null)
                {
                    var squareSpeed = marchNativeData.speed[data.marchIndex];
                    var forward = (Vector3)targetPosition - data.position;
                    var d = forward.magnitude;
                    var speed = squareSpeed * deltaTime * 2.5f;
                    if (speed >= d)
                    {
                        data.state = 1;
                        data.position = targetPosition;
                        for (int j = 0; j < data.childIndex.Count; j++)
                        {
                            var childIndex = data.childIndex[j];
                            var spriteData = childNativeData.animSpriteData[childIndex];
                            spriteData.visible = false;
                            childNativeData.animSpriteData[childIndex] = spriteData;
                            childNativeData.state[childIndex] = 5;
                        }
                        rotation = squareForward;
                    }
                    else
                    {
                        data.position = data.position + speed * forward.normalized;
                        rotation = squareForward;
                        for (int j = 0; j < data.childIndex.Count; j++)
                        {
                            var childIndex = data.childIndex[j];
                            var projChild = Vector3.Dot(childNativeData.position[childIndex] - squarePosition,
                                squareForward);
                            var projAmbulance = Vector3.Dot(data.position - (Vector3)squarePosition, squareForward);
                            if (projAmbulance >= projChild)
                            {
                                var spriteData = childNativeData.animSpriteData[childIndex];
                                spriteData.visible = false;
                                childNativeData.animSpriteData[childIndex] = spriteData;
                                childNativeData.state[childIndex] = 5;
                            }
                        }
                    }
                }
                else
                {
                    data.position = targetPosition;
                    rotation = marchNativeData.forward[data.marchIndex];
                }

                if (data.fadeState == 0)
                {
                    float alpha = time - data.startFadeTime;
                    alpha = Mathf.Clamp(alpha, 0, 1);
                    data.animSprite.alpha = alpha;
                }

                data.animSprite.alpha *= marchNativeData.alpha[data.marchIndex];
                data.animSprite.position = data.position;
                data.animSprite.rotation = rotation;
            }
        }

        #region behaviour

        public void OnLodChanged(int lodLevel)
        {
            var canUpdate = lodLevel < WorldEntry.MaxShowMarchLodLevel;
            if (canUpdate)
            {
                updateState = 0;
            }
            else
            {
                if (updateState == 0)
                {
                    updateState = 1;
                }
            }
        }

        private bool simpleMode;
        private bool needResetForamtion = false;
        
        public void Update(float realTime,float deltaTime)
        {
            if (!Enabled)
            {
                return;
            }
            //先检查删除，因为删除小兵会有交换粒子顺序的操作，必须放在粒子的job之前完成
            CheckRecover();
            UpdateFakeKnockBack();
            UpdateCrossingGate(realTime,deltaTime);
            UpdateAmbulance(realTime,deltaTime);
            UpdateTrucks(realTime,deltaTime);
            if (simpleMode != RTSQualityHelper.IsSimpleMode)
            {
                simpleMode = RTSQualityHelper.IsSimpleMode;
                RemoveAllChildren();
                needResetForamtion = true;
            }
            RemoveSprite();
            if (needResetForamtion)
            {
                needResetForamtion = false;
                currentChildIndex = 0;
                foreach (var keyValue in freeIndexDictionary)
                {
                    keyValue.Value.Clear();
                }
                
                ArmyManager.Instance.MarchManager.ResetFormation();
            }

            if (updateState == 1)
            {
                updateState = 2;
            }
            else if (updateState == 2)
            {
                return;
            }
            ExecuteJob(realTime);
#if UNITY_EDITOR
            if (isDebug)
            {
                for (int i = 0; i < marchNativeData.count; i++)
                {
                    if (!marchNativeData.valid[i])
                    {
                        continue;
                    }

                    if (squares[i])
                    {
                        squares[i].position = marchNativeData.position[i];
                        var forward = marchNativeData.forward[i];
                        if (forward.x == 0 && forward.y == 0 && forward.z == 0)
                        {
                            Debug.LogError(i + "方阵方向错误");
                            marchNativeData.forward[i] = new float3(0, 0, 1);
                        }
                        squares[i].forward = marchNativeData.forward[i];
                    }
                }
                for (int i = 0; i < childNativeData.count; i++)
                {
                    if (!childNativeData.valid[i])
                    {
                        continue;
                    }

                    if (children[i])
                    {
                        children[i].position = childNativeData.position[i];
                        children[i].forward = childNativeData.forward[i];
                    }
                }
            }
#endif
        }

    

        private bool CheckRecover()
        {
            bool hasRecoverSquare = recoverSquareList.Count > 0;
            for (int i = 0; i < recoverSquareList.Count; i++)
            {
                RecoverSquare(recoverSquareList[i]);
            }
            recoverSquareList.Clear();
            return hasRecoverSquare;
        }
        
        #endregion
        

        public void ShowFakeKnockBack(int index, Vector3 forward,int count,int externalSoldierId = -1)
        {
            if (index < 0)
            {
                return;
            }

            float maxX = float.MinValue;
            float minX = float.MaxValue;
            float maxZ = float.MinValue;
            float minZ = float.MaxValue;
            Vector3 centerPosition = default;
            int soldierId = -1;
            
            if (marchNativeData.valid[index])
            {
                if (externalSoldierId >= 0)
                {
                    soldierId = externalSoldierId;
                    var position = marchNativeData.position[index];
                    centerPosition = new Vector3(position.x,0, position.z);
                }
                else
                {
                    var head = marchNativeData.childIndexHead[index];
                    var childCount = marchNativeData.childCount[index];
                    for (int i = head; i < head + childCount; i++)
                    {
                        if (childNativeData.valid[i] && childNativeData.state[i] < 3)
                        {
                            var position = childNativeData.position[i];
                            maxX = Mathf.Max(position.x, maxX);
                            minX = Mathf.Min(position.x, minX);
                            maxZ = Mathf.Max(position.z, maxZ);
                            minZ = Mathf.Min(position.z, minZ);
                            soldierId = childNativeData.soldierId[i];
                        }
                    }

                    if (soldierId == -1)
                    {
                        return;
                    }
                }
                var rtsResManager = ArmyManager.Instance.GetRtsResourceManager();
                var modelName = BattleUtils.GetSoldierModelNameById(soldierId);
                //需要判断一下是不是需要加载资源
                var creator = ArmyManager.GetSpriteCreatorByOriginNameAndTeam(modelName, 0);
                if (creator == null)
                {
                    ArmyManager.LoadAndCreateSoldierSprite(modelName, 0, (loadedCreator) =>
                    {
                        var cv = loadedCreator as CreatorVisitor;
                        if (!soldierAtlasMap.ContainsKey(modelName))
                        {
                            InitSpriteData(cv);
                            soldierAtlasMap.Add(modelName, new SoldierAtlasLoader
                            {
                                creator = cv,
                            });
                        }
                    });
                }
                for (int i = 0; i < count; i++)
                {
                    var team = marchNativeData.team[index];
                    var sprite = ArmyManager.GetSoldierSprite(modelName, 0);
                    if (sprite != null)
                    {
                        Vector3 startPosition;
                        if (externalSoldierId >= 0)
                        {
                            startPosition = centerPosition + Quaternion.AngleAxis(UnityEngine.Random.Range(-90,90),Vector3.up) * forward * UnityEngine.Random.Range(0.5f, 1f);
                        }
                        else
                        {
                            startPosition = new Vector3(UnityEngine.Random.Range(minX, maxX), 0,
                                UnityEngine.Random.Range(minZ, maxZ));
                        }
                        var spriteName = GetSpriteNameByModelNameAndTeam(modelName, 0);
                        var scale = rtsResManager.GetModelScaleByName(modelName) * animSpriteScale;// *  ArmyManager.GetSoldierSpriteCreatorScale(spriteName);
                        sprite.spriteSize = scale;
                        sprite.alpha = 1;
                        sprite.action = SPRITE_ACTION_ENUM.HitFly;
                        sprite.position = startPosition;
                        sprite.team = team;
                        var psIndex = spriteNameToPSIndexDic[spriteName];
                        var data = new FakeKnockBackData
                        {
                            animSprite = sprite,
                            horizontalDistance = UnityEngine.Random.Range(0.2f,0.4f),
                            startForward = forward,
                            startFadeTime = -1,
                            startKnockTime = TimeUtils.GetClientTickTime(),
                            startPosition = startPosition,
                            verticalA = -10f,
                            verticalStartSpeed = UnityEngine.Random.Range(1.2f,2.2f),
                            psIndex = psIndex,
                        };
                        var d = animSpriteData[psIndex];
                        if (d.childIndex[sprite.spriteIndex] > 0)
                        {
                            Debug.LogError("用到了已经使用的小兵 childIndex = " + d.childIndex[sprite.spriteIndex] + " spriteIndex = " + sprite.spriteIndex);
                        }
                        d.childIndex[sprite.spriteIndex] = -1;
                        fakeKnockBackList.Add(data);
                    }
                }
            }
        }

        public void ShowFakeMoveForward(int index,Vector3 startPosition,Vector3 targetPosition)
        {
            if (index < 0)
            {
                return;
            }

            if (marchNativeData.valid[index])
            {
                marchNativeData.status[index] = 1;
                marchNativeData.position[index] = startPosition;
                marchNativeData.forward[index] = targetPosition - startPosition;
                marchNativeData.changeStatusFlag[index] = true;
                marchNativeData.squareStartPosition[index] = startPosition;
                marchNativeData.squareEndPosition[index] = targetPosition;
                marchNativeData.currentSegmentDuration[index] = Vector3.Distance(targetPosition,startPosition) / marchNativeData.speed[index];
                marchNativeData.segmentStartTime[index] = TimeUtils.GetClientTickTime();
                marchNativeData.isServerPosChange[index] = false;
                /*var head = marchNativeData.childIndexHead[index];
                var childCount = marchNativeData.childCount[index];
                for (int i = head; i < head + childCount; i++)
                {
                    if (childNativeData.valid[i] && childNativeData.state[i] < 3)
                    {
                        childNativeData
                    }
                }*/
            }
        }

        public void StopFakeMoveForward(int index,Vector3 targetPosition)
        {
            if (index < 0)
            {
                return;
            }

            if (marchNativeData.valid[index])
            {
                marchNativeData.status[index] = 0;
                marchNativeData.position[index] = targetPosition;
                marchNativeData.changeStatusFlag[index] = true;
                marchNativeData.squareStartPosition[index] = targetPosition;
                marchNativeData.squareEndPosition[index] = targetPosition;
                marchNativeData.currentSegmentDuration[index] = 0;
                marchNativeData.isServerPosChange[index] = true;
            }
        }

        public void CreateTruckAttacker(int id,Vector3 position,Vector3 forward,float speed)
        {
            var truckData = GetTruckData(id,position,forward,speed);
            var formationType = MarchHelper.CrossingGateFormationId;
            var formationConfig = GetBattleFormationConfigByFormationType(formationType,0);
            truckData.resReady = false;
            truckData.valid = true;
            truckData.speed = speed;
            CheckSoldierAtlasReady(formationConfig, () =>
            {
                if (truckData.valid)
                {
                    ShowTruckAttacker(truckData, formationConfig);
                    truckData.resReady = true;
                }
            });
            truckDataDic[id] = truckData;
        }

        private void ShowTruckAttacker(TruckData truckData,BattleFormationCfg formationConfig)
        {
            var location = formationConfig.soldierLocation[0];
            var soldierId = location.id;
            var modelName = BattleUtils.GetSoldierModelNameById(soldierId);

            var creator = soldierAtlasMap[modelName].creator;
            var sprite = ArmyManager.GetSoldierSprite(creator);
            sprite.offset = Vector3.zero;
            sprite.spriteSize = ArmyManager.Instance.ResourceManager.GetModelScaleByName(modelName) *
                                animSpriteScale;// * 3;
            sprite.team = 0;
            truckData.animSprite = sprite;
            sprite.rotation = truckData.forward;
            sprite.action = SPRITE_ACTION_ENUM.RUN;
            sprite.NeedRefreshFlag = true;
            var index = spriteNameToPSIndexDic[GetSpriteNameByModelNameAndTeam(modelName, 0)];
            truckData.psIndex = index;
            var d = animSpriteData[index];
            if (d.childIndex[sprite.spriteIndex] > 0)
            {
                Debug.LogError("用到了已经使用的小兵 childIndex = " + d.childIndex[sprite.spriteIndex] + " spriteIndex = " + sprite.spriteIndex);
            }
            d.childIndex[sprite.spriteIndex] = -1;
        }

        private void UpdateTrucks(float time,float deltaTime)
        {
            foreach (var item in truckDataDic)
            {
                var data = item.Value;
                var forward = data.targetPosition - data.position;
                var d = forward.magnitude;
                var speed = data.speed * deltaTime;
                if (speed >= d)
                {
                    data.state = 1;
                }
                data.position += speed * forward.normalized;
                data.animSprite.position = data.position;
                data.animSprite.rotation = forward;
            }
        }

        private TruckData GetTruckData(int id,Vector3 position,Vector3 forward,float speed)
        {
            var targetPosition = forward * speed * 5;
            return new TruckData
            {
                position = position,
                startPosition = position,
                targetPosition = targetPosition,
            };
        }


        private bool showSphere = false;
        public void ShowAllChildrenSphere()
        {
            showSphere = true;
            for (int i = 0; i < children.Count; i++)
            {
                if (children[i])
                {
                    AddSphere(children[i]);
                }
            }   
        }

        private static Vector3 defaultSphereVec3 = new Vector3(0.1f, 0.1f, 0.1f);
        private List<SoldierLocation> formationPos;

        private void AddSphere(Transform parent)  
        {
            var sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            sphere.transform.SetParent(parent);
            sphere.transform.localPosition = Vector3.zero;
            sphere.transform.localScale = defaultSphereVec3;
        }

        public void EditorResetScale()
        {
            var rtsResManager = ArmyManager.Instance.ResourceManager;
            for (int i = 0; i < childNativeData.count; i++)
            {
                if (childNativeData.valid[i])
                {
                    var modelName = BattleUtils.GetSoldierModelNameById(childNativeData.soldierId[i]);
                    var scale = rtsResManager.GetModelScaleByName(modelName) * animSpriteScale;
                    var d = childNativeData.animSpriteData[i];
                    d.spriteOriginScale = scale;
                    childNativeData.animSpriteData[i] = d;
                }
            }

            for (int i = 0; i < animSpriteData.Count; i++)
            {
                for (int j = 0; j < animSpriteData[i].count; j++)
                {
                    var data = animSpriteData[i];
                    if (!data.isShadow[i])
                    {
                        data.spriteSizes[j] = 0;
                    }
                    
                }
            }
        }

        public void ResetSoldierShadowPosition()
        {
            var rtsResManager = ArmyManager.Instance.ResourceManager;
            for (int i = 0; i < childNativeData.count; i++)
            {
                if (childNativeData.valid[i])
                {
                    var modelName = BattleUtils.GetSoldierModelNameById(childNativeData.soldierId[i]);
                    var offset = rtsResManager.GetModelShadowOffsetByName(modelName);
                    var d = childNativeData.animSpriteData[i];
                    d.shadowOffset = offset;
                    childNativeData.animSpriteData[i] = d;
                }
            }
        }

        public void Reset()
        {
            currentChildIndex = 0;
            currentMarchIndex = 0;
        }

        public void RemoveAllChildren()
        {
            //先删除所有小兵
            for (int index = 0; index < marchNativeData.count; index++)
            {
                var childHead = marchNativeData.childIndexHead[index];
                var childCount = marchNativeData.childCount[index];

                for (int i = childHead; i < childHead + childCount; i++)
                {
                    //删除以前的小兵
                    RemoveAnimSprite(i);
                    RemoveShadowSprite(i);
                    childNativeData.state[i] = 0;
                    childNativeData.valid[i] = false;
                }
            }

            if (children != null)
            {
                for (int i = 0; i < children.Count; i++)
                {
                    if (children[i] && children[i].Valid())
                    {
                        GameObject.Destroy(children[i].gameObject);
                        children[i] = null;
                    }
                }
            }
            loadSoldierAtlasCallBackMap.Clear();
        }

        public void ExpandNativeArray()
        {
            ExpandMarchNativeArray();
            ExpandChildNativeArray();
        }

        private void ExpandMarchNativeArray()
        {
            if (marchNativeArrayLength == MAX_MARCH_COUNT)
            {
                Debug.LogError("March满了");
                return;
            }
            marchNativeArrayLength = Mathf.Min(marchNativeArrayLength * 2, MAX_MARCH_COUNT);
            var marchNativeData = this.marchNativeData;
            marchNativeData.count = marchNativeArrayLength;
            marchNativeData.position = BattleUtils.GetExpendedArray(marchNativeData.position, marchNativeArrayLength);
#if UNITY_EDITOR
            marchNativeData.marchId = BattleUtils.GetExpendedArray(marchNativeData.marchId, marchNativeArrayLength);
#endif
            marchNativeData.valid = BattleUtils.GetExpendedArray(marchNativeData.valid,marchNativeArrayLength);
            marchNativeData.forward = BattleUtils.GetExpendedArray(marchNativeData.forward,marchNativeArrayLength);
            marchNativeData.index = BattleUtils.GetExpendedArray(marchNativeData.index,marchNativeArrayLength);
            marchNativeData.childIndexHead = BattleUtils.GetExpendedArray( marchNativeData.childIndexHead,marchNativeArrayLength);
            marchNativeData.childCount = BattleUtils.GetExpendedArray(marchNativeData.childCount,marchNativeArrayLength);
            marchNativeData.formationId = BattleUtils.GetExpendedArray(marchNativeData.formationId,marchNativeArrayLength);
            marchNativeData.TurnState = BattleUtils.GetExpendedArray(marchNativeData.TurnState,marchNativeArrayLength);
            marchNativeData.needCalculateChildren = BattleUtils.GetExpendedArray(marchNativeData.needCalculateChildren,marchNativeArrayLength);
            marchNativeData.formationPositionIndexOffset = BattleUtils.GetExpendedArray(marchNativeData.formationPositionIndexOffset,marchNativeArrayLength);
            marchNativeData.needForceMoveChildren = BattleUtils.GetExpendedArray(marchNativeData.needForceMoveChildren,marchNativeArrayLength);
            marchNativeData.speed = BattleUtils.GetExpendedArray(marchNativeData.speed,marchNativeArrayLength);
            marchNativeData.squareStartPosition = BattleUtils.GetExpendedArray(marchNativeData.squareStartPosition,marchNativeArrayLength);
            marchNativeData.squareEndPosition = BattleUtils.GetExpendedArray(marchNativeData.squareEndPosition,marchNativeArrayLength);
            marchNativeData.currentSegmentDuration = BattleUtils.GetExpendedArray(marchNativeData.currentSegmentDuration,marchNativeArrayLength);
            marchNativeData.status = BattleUtils.GetExpendedArray(marchNativeData.status,marchNativeArrayLength);
            marchNativeData.changeStatusFlag = BattleUtils.GetExpendedArray(marchNativeData.changeStatusFlag,marchNativeArrayLength);
            marchNativeData.team = BattleUtils.GetExpendedArray(marchNativeData.team,marchNativeArrayLength);
            marchNativeData.alpha = BattleUtils.GetExpendedArray(marchNativeData.alpha,marchNativeArrayLength);
            marchNativeData.overrideAlpha = BattleUtils.GetExpendedArray(marchNativeData.overrideAlpha,marchNativeArrayLength);
            marchNativeData.initSoldierNum = BattleUtils.GetExpendedArray(marchNativeData.initSoldierNum,marchNativeArrayLength);
            marchNativeData.curSoldierNum = BattleUtils.GetExpendedArray(marchNativeData.curSoldierNum,marchNativeArrayLength);
            marchNativeData.soldierTypeList = BattleUtils.GetExpendedArray(marchNativeData.soldierTypeList,marchNativeArrayLength);
            marchNativeData.isServerPosChange = BattleUtils.GetExpendedArray(marchNativeData.isServerPosChange,marchNativeArrayLength);
            marchNativeData.isBesiege = BattleUtils.GetExpendedArray(marchNativeData.isBesiege,marchNativeArrayLength);
            marchNativeData.segmentStartTime = BattleUtils.GetExpendedArray(marchNativeData.segmentStartTime,marchNativeArrayLength);
            marchNativeData.isClientInBattle = BattleUtils.GetExpendedArray(marchNativeData.isClientInBattle,marchNativeArrayLength);
            marchNativeData.isEscape = BattleUtils.GetExpendedArray(marchNativeData.isEscape,marchNativeArrayLength);
            this.marchNativeData = marchNativeData;
        }

        private void ExpandChildNativeArray()
        {
            if (childNativeArrayLength == MAX_CHILD_COUNT)
            {
                Debug.LogError("Child满了");
                return;
            }

            childNativeArrayLength = Mathf.Min(childNativeArrayLength * 2, MAX_CHILD_COUNT);
            var childNativeData = this.childNativeData;
            childNativeData.count = childNativeArrayLength;
            childNativeData.valid = BattleUtils.GetExpendedArray(childNativeData.valid,childNativeArrayLength);
            childNativeData.index = BattleUtils.GetExpendedArray(childNativeData.index,childNativeArrayLength);
            childNativeData.postionIndex = BattleUtils.GetExpendedArray(childNativeData.postionIndex, childNativeArrayLength);
            childNativeData.position = BattleUtils.GetExpendedArray(childNativeData.position,childNativeArrayLength);
            childNativeData.forward = BattleUtils.GetExpendedArray(childNativeData.forward,childNativeArrayLength);
            childNativeData.direction = BattleUtils.GetExpendedArray(childNativeData.direction,childNativeArrayLength);
            childNativeData.targetForward = BattleUtils.GetExpendedArray(childNativeData.targetForward,childNativeArrayLength);
            childNativeData.targetDirection = BattleUtils.GetExpendedArray(childNativeData.targetDirection,childNativeArrayLength);
            childNativeData.animSpriteIndex = BattleUtils.GetExpendedArray(childNativeData.animSpriteIndex,childNativeArrayLength);
            childNativeData.shadowSpriteIndex = BattleUtils.GetExpendedArray(childNativeData.shadowSpriteIndex,childNativeArrayLength);
            childNativeData.animSpriteData = BattleUtils.GetExpendedArray(childNativeData.animSpriteData,childNativeArrayLength);
            childNativeData.animPSIndex = BattleUtils.GetExpendedArray(childNativeData.animPSIndex,childNativeArrayLength);
            childNativeData.shadowPSIndex = BattleUtils.GetExpendedArray(childNativeData.shadowPSIndex,childNativeArrayLength);
            childNativeData.state = BattleUtils.GetExpendedArray(childNativeData.state,childNativeArrayLength);
            childNativeData.subState = BattleUtils.GetExpendedArray(childNativeData.subState,childNativeArrayLength);
            childNativeData.soldierType = BattleUtils.GetExpendedArray(childNativeData.soldierType,childNativeArrayLength);
            childNativeData.alpha = BattleUtils.GetExpendedArray(childNativeData.alpha, childNativeArrayLength);
            childNativeData.soldierId = BattleUtils.GetExpendedArray(childNativeData.soldierId,childNativeArrayLength);
            childNativeData.startMovePosition = BattleUtils.GetExpendedArray(childNativeData.startMovePosition,childNativeArrayLength);
            childNativeData.targetMovePosition = BattleUtils.GetExpendedArray(childNativeData.targetMovePosition,childNativeArrayLength);
            childNativeData.childTargetPosition = BattleUtils.GetExpendedArray(childNativeData.childTargetPosition,childNativeArrayLength);
            childNativeData.moveNeedTime = BattleUtils.GetExpendedArray(childNativeData.moveNeedTime,childNativeArrayLength);
            childNativeData.moveStartTime = BattleUtils.GetExpendedArray(childNativeData.moveStartTime,childNativeArrayLength);
            childNativeData.rotateStartTime = BattleUtils.GetExpendedArray(childNativeData.rotateStartTime,childNativeArrayLength);
            childNativeData.InAdjustPositionState = BattleUtils.GetExpendedArray(childNativeData.InAdjustPositionState,childNativeArrayLength);
            childNativeData.IsFirstChange = BattleUtils.GetExpendedArray(childNativeData.IsFirstChange,childNativeArrayLength);
            childNativeData.stageStartTime = BattleUtils.GetExpendedArray(childNativeData.stageStartTime,childNativeArrayLength);
            childNativeData.instructionSetIndex = BattleUtils.GetExpendedArray(childNativeData.instructionSetIndex,childNativeArrayLength);
            childNativeData.waitTime = BattleUtils.GetExpendedArray(childNativeData.waitTime,childNativeArrayLength);
            childNativeData.actionIndex = BattleUtils.GetExpendedArray(childNativeData.actionIndex,childNativeArrayLength);
            childNativeData.actionConfigId = BattleUtils.GetExpendedArray(childNativeData.actionConfigId,childNativeArrayLength);
            childNativeData.transformOffset = BattleUtils.GetExpendedArray(childNativeData.transformOffset,childNativeArrayLength);
            this.childNativeData = childNativeData;
        }

        public void CheckChildData()
        {
            Dictionary<int, HashSet<int>> dic = new Dictionary<int, HashSet<int>>();
            for (int i = 0; i < childNativeData.count; i++)
            {
                if (childNativeData.valid[i])
                {
                    if (!dic.TryGetValue(childNativeData.animPSIndex[i], out var dicc))
                    {
                        dicc = new HashSet<int>();
                        dic.Add(childNativeData.animPSIndex[i],dicc);
                    }

                    if (dicc.Contains(childNativeData.animSpriteIndex[i]))
                    {
                        Debug.LogError("小兵重复了 "+i);
                    }
                    else
                    {
                        dicc.Add(childNativeData.animSpriteIndex[i]);
                    }
                }
            }
        }

        public void PrintChildData()
        {
            for (int i = 0; i < childNativeData.count; i++)
            {
                if (childNativeData.valid[i])
                {
                    Debug.LogError("小兵" + i + "的序列帧为" + childNativeData.animPSIndex[i] + "_" + childNativeData.animSpriteIndex[i]);
                }
            }
        }

        //todo 先通过方阵判断是否有异步加载的情况，减少字典索引次数
        private void TryRemoveSoldierAtlasCallback(int childIndex)
        {
            loadSoldierAtlasCallBackMap.Remove(childIndex);
        }
        
        
        public void Dispose()
        {
            
            if (_isDisposed)
            {
                return;
            }
            _isDisposed = true;
            if (marchNativeData.inited)
            {
                marchNativeData.inited = false;
                marchNativeData.position.Dispose();
#if UNITY_EDITOR
                marchNativeData.marchId.Dispose();
#endif
                marchNativeData.valid.Dispose();
                marchNativeData.forward.Dispose();
                marchNativeData.index.Dispose();
                marchNativeData.childIndexHead.Dispose();
                marchNativeData.childCount.Dispose();
                marchNativeData.formationId.Dispose();
                marchNativeData.TurnState.Dispose();
                marchNativeData.needCalculateChildren.Dispose();
                marchNativeData.needForceMoveChildren.Dispose();
                marchNativeData.formationPositionIndexOffset.Dispose();
                marchNativeData.speed.Dispose();
                marchNativeData.squareStartPosition.Dispose();
                marchNativeData.squareEndPosition.Dispose();
                marchNativeData.currentSegmentDuration.Dispose();
                marchNativeData.status.Dispose();
                marchNativeData.changeStatusFlag.Dispose();
                marchNativeData.team.Dispose();
                marchNativeData.alpha.Dispose();
                marchNativeData.overrideAlpha.Dispose();
                marchNativeData.initSoldierNum.Dispose();
                marchNativeData.curSoldierNum.Dispose();
                marchNativeData.soldierTypeList.Dispose();
                marchNativeData.isServerPosChange.Dispose();
                marchNativeData.isBesiege.Dispose();
                marchNativeData.segmentStartTime.Dispose();
                marchNativeData.isClientInBattle.Dispose();
                marchNativeData.isEscape.Dispose();
                //marchNativeData.pathData.Dispose();
            }

            if (childNativeData.inited)
            {
                childNativeData.inited = false;
                childNativeData.valid.Dispose();
                childNativeData.index.Dispose();
                childNativeData.postionIndex.Dispose();
                childNativeData.position.Dispose();
                childNativeData.forward.Dispose();
                childNativeData.direction.Dispose();
                childNativeData.targetForward.Dispose();
                childNativeData.targetDirection.Dispose();
                childNativeData.animSpriteIndex.Dispose();
                childNativeData.shadowSpriteIndex.Dispose();
                childNativeData.animSpriteData.Dispose();
                childNativeData.animPSIndex.Dispose();
                childNativeData.shadowPSIndex.Dispose();
                childNativeData.state.Dispose();
                childNativeData.subState.Dispose();
                childNativeData.soldierType.Dispose();
                childNativeData.soldierId.Dispose();
                childNativeData.alpha.Dispose();
                childNativeData.startMovePosition.Dispose();
                childNativeData.targetMovePosition.Dispose();
                childNativeData.childTargetPosition.Dispose();
                childNativeData.moveNeedTime.Dispose();
                childNativeData.moveStartTime.Dispose();
                childNativeData.rotateStartTime.Dispose();
                childNativeData.InAdjustPositionState.Dispose();
                childNativeData.IsFirstChange.Dispose();
                childNativeData.stageStartTime.Dispose();
                childNativeData.instructionSetIndex.Dispose();
                childNativeData.waitTime.Dispose();
                childNativeData.actionIndex.Dispose();
                childNativeData.actionConfigId.Dispose();
                childNativeData.transformOffset.Dispose();
                //childNativeData.movementData.Dispose();
            }
            
            if (animSpriteData != null)
            {
                for (int i = 0; i < animSpriteData.Count; i++)
                {
                    animSpriteData[i].childIndex.Dispose();
                    animSpriteData[i].valid.Dispose();
                    animSpriteData[i].isShadow.Dispose();
                }

            }
           
            directions.Dispose();
            useActionIds.Dispose();
            actionInfos.Dispose();
            
//            soldierPositionIndexNativeArray.Dispose();
//            soldierPositionIndexArray235to325.Dispose();
//            soldierPositionIndexArray135to180.Dispose();
//            soldierPositionIndexArray45To135Degree.Dispose();
            soldierPositionIndexNativeArrays.Dispose();
            if (attackDataReady)
            {
                attackActionData.Dispose();
                attackActionConfigData.Dispose();
                localPositionsNativeIndex.Dispose();
                localPositionsNative.Dispose();
                battlePositionsNative.Dispose();
            }
           

            spriteDataReady = false;
            attackDataReady = false;

            attackActions = null;
            attackActionConfigs = null;

            for (int i = 0; i < fakeKnockBackList.Count; i++)
            {
                var sprite = fakeKnockBackList[i].animSprite;
                //ArmyManager.RemoveSprite(sprite);
                RemoveSprite(sprite, sprite.psIndex);
            }
            fakeKnockBackList.Clear();

            for (int i = 0; i < ambulanceList.Count; i++)
            {
                //ArmyManager.RemoveSprite(ambulanceList[i].animSprite);
                RemoveSprite(ambulanceList[i].animSprite, ambulanceList[i].animSprite.psIndex);
            }
            ambulanceList.Clear();
			
            animSprites = null;
            loadSoldierAtlasCallBackMap.Clear();
            soldierAtlasMap.Clear();
            //shadowSprites = null;
        }
    }
}
